diff --git a/src/app/firedancer-dev/commands/backtest.c b/src/app/firedancer-dev/commands/backtest.c index d9994bfeae2..037ae3b529e 100644 --- a/src/app/firedancer-dev/commands/backtest.c +++ b/src/app/firedancer-dev/commands/backtest.c @@ -30,16 +30,169 @@ #include "../../../flamenco/runtime/context/fd_capture_ctx.h" #include "../../../disco/pack/fd_pack_cost.h" #include "../../../flamenco/progcache/fd_progcache_admin.h" +#include "../../../flamenco/runtime/tests/ledgers.h" +#include "../../shared/fd_config_private.h" +#include "../../platform/fd_file_util.h" #include "../main.h" #include #include #include +#include +#include +#include +#include +#include +#include +#include extern fd_topo_obj_callbacks_t * CALLBACKS[]; fd_topo_run_tile_t fdctl_tile_run( fd_topo_tile_t const * tile ); +/* Global variable to store ledger name for access in topo function */ +static char g_ledger_name[64] = {0}; + +/* Global variable to store custom ledger config */ +static fd_ledger_config_t g_custom_ledger_config = {0}; +static int g_has_custom_config = 0; + +/* Global variable to store user config path for reloading after ledger config */ +static char g_user_config_path[256] = {0}; + +/* Forward declarations */ +static void apply_ledger_config( fd_ledger_config_t const * ledger_config, config_t * config ); +void backtest_topo_initialize( config_t * config ); +void backtest_clear_custom_config( void ); + +/* Function to set user config path from main.c */ +void +backtest_set_user_config_path( char const * config_path ) { + if( config_path ) { + strncpy( g_user_config_path, config_path, sizeof(g_user_config_path) - 1 ); + g_user_config_path[ sizeof(g_user_config_path) - 1 ] = '\0'; + } else { + g_user_config_path[0] = '\0'; + } +} + +/* Function to set the ledger name from main.c */ +void +backtest_set_ledger_name( char const * ledger_name ) { + if( ledger_name ) { + strncpy( g_ledger_name, ledger_name, sizeof(g_ledger_name) - 1 ); + g_ledger_name[ sizeof(g_ledger_name) - 1 ] = '\0'; + } +} + +/* Function to set custom ledger configuration from main.c (called early before argument parsing) */ +void +backtest_set_custom_config( fd_ledger_config_t * config ) { + if( config ) { + g_custom_ledger_config = *config; + g_has_custom_config = 1; + FD_LOG_NOTICE(( "Custom ledger configuration set from main function" )); + } +} + +/* Function to create custom ledger configuration from command-line arguments (called early in main.c) */ +void +backtest_create_custom_config_from_args( int argc, char ** argv ) { + /* Check if this is a child process (has --no-watch) */ + int is_child_process = 0; + for( int i = 1; i < argc; i++ ) { + if( strcmp( argv[i], "--no-watch" ) == 0 ) { + is_child_process = 1; + backtest_clear_custom_config(); + break; + } + } + + /* Even for child processes, we need to parse the ledger name so config can be applied */ + /* Parse ledger name (should be the first non-flag argument, but skip "backtest" if present) */ + for( int i = 1; i < argc; i++ ) { + if( strncmp( argv[i], "--", 2 ) != 0 && strcmp( argv[i], "backtest" ) != 0 ) { + backtest_set_ledger_name( argv[i] ); + break; + } + } + + /* Skip custom configuration creation if this is a child process */ + if( is_child_process ) { + return; /* This is a child process, skip custom config creation */ + } + + /* Check if any custom configuration flags were provided */ + int has_custom_flags = 0; + for( int i = 1; i < argc; i++ ) { + if( strcmp( argv[i], "--genesis" ) == 0 || + strcmp( argv[i], "--has-incremental" ) == 0 || + strncmp( argv[i], "--cluster-version", 17 ) == 0 || + strncmp( argv[i], "--funk-pages", 12 ) == 0 || + strncmp( argv[i], "--index-max", 11 ) == 0 || + strncmp( argv[i], "--end-slot", 10 ) == 0 ) { + has_custom_flags = 1; + break; + } + } + + if( has_custom_flags ) { + FD_LOG_NOTICE(( "Custom configuration flags detected. Creating custom ledger configuration." )); + + /* Create custom configuration */ + fd_ledger_config_t custom_config = {0}; + + /* Set the ledger name (should be the first non-flag argument, but skip "backtest" if present) */ + for( int i = 1; i < argc; i++ ) { + if( strncmp( argv[i], "--", 2 ) != 0 && strcmp( argv[i], "backtest" ) != 0 ) { + snprintf( custom_config.name, FD_LEDGER_NAME_MAX_LEN, "%s", argv[i] ); + backtest_set_ledger_name( argv[i] ); + break; + } + } + + /* Parse flags and set configuration */ + for( int i = 1; i < argc; i++ ) { + if( strcmp( argv[i], "--genesis" ) == 0 ) { + custom_config.genesis = 1; + } else if( strcmp( argv[i], "--has-incremental" ) == 0 ) { + custom_config.has_incremental = 1; + } else if( strncmp( argv[i], "--cluster-version", 17 ) == 0 && i + 1 < argc ) { + snprintf( custom_config.cluster_version, FD_LEDGER_CLUSTER_VERSION_MAX_LEN, "%s", argv[i + 1] ); + i++; /* Skip the value */ + } else if( strncmp( argv[i], "--funk-pages", 12 ) == 0 && i + 1 < argc ) { + custom_config.funk_pages = (ulong)strtoul( argv[i + 1], NULL, 10 ); + i++; /* Skip the value */ + } else if( strncmp( argv[i], "--index-max", 11 ) == 0 && i + 1 < argc ) { + custom_config.index_max = (ulong)strtoul( argv[i + 1], NULL, 10 ); + i++; /* Skip the value */ + } else if( strncmp( argv[i], "--end-slot", 10 ) == 0 && i + 1 < argc ) { + custom_config.end_slot = (ulong)strtoul( argv[i + 1], NULL, 10 ); + i++; /* Skip the value */ + } + } + + /* Set defaults for unspecified values */ + if( custom_config.cluster_version[0] == '\0' ) { + snprintf( custom_config.cluster_version, FD_LEDGER_CLUSTER_VERSION_MAX_LEN, "mainnet" ); + } + if( custom_config.funk_pages == 0 ) { + custom_config.funk_pages = 1UL; + } + + /* Set the custom configuration */ + backtest_set_custom_config( &custom_config ); + } + /* Note: Ledger name parsing is done above before checking for custom flags */ +} + +/* Function to clear custom ledger configuration (for child processes) */ +void +backtest_clear_custom_config( void ) { + g_has_custom_config = 0; + memset( &g_custom_ledger_config, 0, sizeof(g_custom_ledger_config) ); +} + static void backtest_topo( config_t * config ) { @@ -315,6 +468,80 @@ backtest_topo( config_t * config ) { extern int * fd_log_private_shared_lock; +/* Custom topo initialize function that applies ledger configuration before calling fd_topo_initialize */ +void +backtest_topo_initialize( config_t * config ) { + /* Always set archiver ingest mode to rocksdb for backtest (required before fd_topo_initialize) */ + strncpy( config->tiles.archiver.ingest_mode, "rocksdb", sizeof(config->tiles.archiver.ingest_mode) - 1 ); + config->tiles.archiver.ingest_mode[ sizeof(config->tiles.archiver.ingest_mode) - 1 ] = '\0'; + config->tiles.archiver.enabled = 1; + + /* Set default rocksdb_path - will be overridden by apply_ledger_config if ledger is provided */ + char * dump_dir = getenv("DUMP_DIR"); + if( dump_dir == NULL ) { + dump_dir = "dump"; + } + strncpy( config->tiles.archiver.rocksdb_path, dump_dir, sizeof(config->tiles.archiver.rocksdb_path) - 1 ); + config->tiles.archiver.rocksdb_path[ sizeof(config->tiles.archiver.rocksdb_path) - 1 ] = '\0'; + strncat( config->tiles.archiver.rocksdb_path, "/placeholder/rocksdb", sizeof(config->tiles.archiver.rocksdb_path) - strlen(config->tiles.archiver.rocksdb_path) - 1 ); + config->tiles.archiver.rocksdb_path[ sizeof(config->tiles.archiver.rocksdb_path) - 1 ] = '\0'; + + /* Apply ledger configuration if provided - this needs to happen before + fd_topo_initialize is called, but after default TOML is loaded */ + if( g_ledger_name[0] != '\0' && strcmp( g_ledger_name, "backtest" ) != 0 ) { + fd_ledger_config_t const * ledger_config = fd_ledger_config_find( g_ledger_name ); + if( !ledger_config ) { + if( g_has_custom_config ) { + /* Check if the custom config name matches the current ledger name */ + /* If not, this might be a child process with inherited custom config */ + if( strcmp( g_custom_ledger_config.name, g_ledger_name ) != 0 ) { + FD_LOG_NOTICE(( "Custom config name mismatch (custom=%s, ledger=%s), clearing custom config", g_custom_ledger_config.name, g_ledger_name )); + g_has_custom_config = 0; + memset( &g_custom_ledger_config, 0, sizeof(g_custom_ledger_config) ); + /* Try to find predefined config again */ + ledger_config = fd_ledger_config_find( g_ledger_name ); + if( !ledger_config ) { + /* If no predefined config and custom config doesn't match, + defer to backtest_cmd_fn to handle custom config creation */ + FD_LOG_NOTICE(( "Ledger configuration not found for: %s. Will check for custom flags.", g_ledger_name )); + /* Continue without applying config - it will be applied in backtest_cmd_fn if custom flags are provided */ + } else { + apply_ledger_config( ledger_config, config ); + } + } else { + FD_LOG_NOTICE(( "Using custom ledger configuration for: %s", g_ledger_name )); + apply_ledger_config( &g_custom_ledger_config, config ); + } + } else { + /* No custom config available yet - it will be created in backtest_cmd_fn if custom flags are provided */ + FD_LOG_NOTICE(( "Ledger configuration not found for: %s. Will check for custom flags in command args.", g_ledger_name )); + /* Continue without applying config - it will be applied in backtest_cmd_fn if custom flags are provided */ + } + } else { + apply_ledger_config( ledger_config, config ); + } + } + + /* After applying ledger config, reload user TOML config if provided */ + /* This allows TOML config to override ledger config values */ + if( g_user_config_path[0] != '\0' ) { + ulong user_config_sz = 0UL; + char * user_config = fd_file_util_read_all( g_user_config_path, &user_config_sz ); + if( FD_UNLIKELY( user_config == MAP_FAILED ) ) { + FD_LOG_ERR(( "failed to reload user config file `%s` (%d-%s)", g_user_config_path, errno, fd_io_strerror( errno ) )); + } else { + fd_config_load_buf( config, user_config, user_config_sz, g_user_config_path ); + fd_config_validate( config ); + if( FD_UNLIKELY( -1 == munmap( user_config, user_config_sz ) ) ) { + FD_LOG_WARNING(( "munmap() failed (%i-%s)", errno, fd_io_strerror( errno ) )); + } + } + } + + /* Call the original topo initialize function */ + fd_topo_initialize( config ); +} + static void backtest_cmd_topo( config_t * config ) { backtest_topo( config ); @@ -338,7 +565,68 @@ void backtest_cmd_args( int * pargc, char *** pargv, args_t * args ) { + /* Initialize backtest args */ + args->backtest.no_watch = 0; + args->backtest.ci_mode = 0; + args->backtest.ledger_name[0] = '\0'; + args->backtest.cluster_version[0] = '\0'; + args->backtest.funk_pages = 0; + args->backtest.index_max = 0; + args->backtest.end_slot = 0; + args->backtest.genesis = 0; + args->backtest.has_incremental = 0; + + /* Parse flags */ args->backtest.no_watch = fd_env_strip_cmdline_contains( pargc, pargv, "--no-watch" ); + args->backtest.ci_mode = fd_env_strip_cmdline_contains( pargc, pargv, "--ci" ); + args->backtest.genesis = fd_env_strip_cmdline_contains( pargc, pargv, "--genesis" ); + args->backtest.has_incremental = fd_env_strip_cmdline_contains( pargc, pargv, "--has-incremental" ); + + /* Parse ledger name (first non-flag argument) */ + if( *pargc > 0 && strncmp( **pargv, "--", 2 ) ) { + strncpy( args->backtest.ledger_name, **pargv, sizeof(args->backtest.ledger_name) - 1 ); + args->backtest.ledger_name[ sizeof(args->backtest.ledger_name) - 1 ] = '\0'; + (*pargc)--; + (*pargv)++; + } + + /* Parse custom configuration flags */ + for( int i = 0; i < *pargc; i++ ) { + if( strncmp( (*pargv)[i], "--cluster-version", 17 ) == 0 && i + 1 < *pargc ) { + strncpy( args->backtest.cluster_version, (*pargv)[i + 1], sizeof(args->backtest.cluster_version) - 1 ); + args->backtest.cluster_version[ sizeof(args->backtest.cluster_version) - 1 ] = '\0'; + /* Remove both the flag and its value */ + for( int j = i; j < *pargc - 2; j++ ) { + (*pargv)[j] = (*pargv)[j + 2]; + } + *pargc -= 2; + i--; /* Adjust index since we removed items */ + } else if( strncmp( (*pargv)[i], "--funk-pages", 12 ) == 0 && i + 1 < *pargc ) { + args->backtest.funk_pages = (ulong)strtoul( (*pargv)[i + 1], NULL, 10 ); + /* Remove both the flag and its value */ + for( int j = i; j < *pargc - 2; j++ ) { + (*pargv)[j] = (*pargv)[j + 2]; + } + *pargc -= 2; + i--; /* Adjust index since we removed items */ + } else if( strncmp( (*pargv)[i], "--index-max", 11 ) == 0 && i + 1 < *pargc ) { + args->backtest.index_max = (ulong)strtoul( (*pargv)[i + 1], NULL, 10 ); + /* Remove both the flag and its value */ + for( int j = i; j < *pargc - 2; j++ ) { + (*pargv)[j] = (*pargv)[j + 2]; + } + *pargc -= 2; + i--; /* Adjust index since we removed items */ + } else if( strncmp( (*pargv)[i], "--end-slot", 10 ) == 0 && i + 1 < *pargc ) { + args->backtest.end_slot = (ulong)strtoul( (*pargv)[i + 1], NULL, 10 ); + /* Remove both the flag and its value */ + for( int j = i; j < *pargc - 2; j++ ) { + (*pargv)[j] = (*pargv)[j + 2]; + } + *pargc -= 2; + i--; /* Adjust index since we removed items */ + } + } } void @@ -350,12 +638,328 @@ backtest_cmd_perm( args_t * args FD_PARAM_UNUSED, run_cmd_perm( NULL, chk, config ); } +/* Function to create custom ledger configuration from command-line arguments */ static void -backtest_cmd_fn( args_t * args FD_PARAM_UNUSED, +create_custom_ledger_config( args_t * args ) { + if( args->backtest.ledger_name[0] == '\0' ) { + return; /* No ledger name provided */ + } + + /* Skip custom configuration creation if this is a child process (has --no-watch) */ + if( args->backtest.no_watch ) { + FD_LOG_NOTICE(( "Child process detected, clearing custom config" )); + /* Clear any inherited custom config from parent process */ + g_has_custom_config = 0; + memset( &g_custom_ledger_config, 0, sizeof(g_custom_ledger_config) ); + return; /* This is a child process, skip custom config creation */ + } + + /* Check if any custom configuration flags were provided */ + int has_custom_flags = 0; + if( args->backtest.cluster_version[0] != '\0' || + args->backtest.funk_pages != 0 || + args->backtest.index_max != 0 || + args->backtest.end_slot != 0 || + args->backtest.genesis || + args->backtest.has_incremental ) { + has_custom_flags = 1; + } + + if( !has_custom_flags ) { + return; + } + + /* Initialize custom config with defaults */ + memset( &g_custom_ledger_config, 0, sizeof(g_custom_ledger_config) ); + + /* Set the name */ + snprintf( g_custom_ledger_config.name, FD_LEDGER_NAME_MAX_LEN, "%s", args->backtest.ledger_name ); + + /* Set cluster version (default to "mainnet" if not provided) */ + if( args->backtest.cluster_version[0] != '\0' ) { + snprintf( g_custom_ledger_config.cluster_version, FD_LEDGER_CLUSTER_VERSION_MAX_LEN, "%s", args->backtest.cluster_version ); + } else { + snprintf( g_custom_ledger_config.cluster_version, FD_LEDGER_CLUSTER_VERSION_MAX_LEN, "mainnet" ); + } + + /* Set numeric values (use defaults if not provided) */ + g_custom_ledger_config.funk_pages = args->backtest.funk_pages ? args->backtest.funk_pages : 1UL; + g_custom_ledger_config.index_max = args->backtest.index_max ? args->backtest.index_max : 0UL; + g_custom_ledger_config.end_slot = args->backtest.end_slot ? args->backtest.end_slot : 0UL; + + /* Set boolean flags */ + g_custom_ledger_config.genesis = args->backtest.genesis; + g_custom_ledger_config.has_incremental = args->backtest.has_incremental; + + g_has_custom_config = 1; + FD_LOG_NOTICE(( "Created custom ledger configuration for: %s", g_custom_ledger_config.name )); +} + +static void +apply_ledger_config( fd_ledger_config_t const * ledger_config, config_t * config ) { + if( !ledger_config ) return; + + char * dump_dir = getenv("DUMP_DIR"); + if( dump_dir == NULL ) { + dump_dir = "dump"; + } + + // create var for ledger_path and set to dump_dir/ledger_config->name + char ledger_path[1024]; + strncpy( ledger_path, dump_dir, sizeof(ledger_path) - 1 ); + ledger_path[ sizeof(ledger_path) - 1 ] = '\0'; + strncat( ledger_path, "/", sizeof(ledger_path) - strlen(ledger_path) - 1 ); + ledger_path[ sizeof(ledger_path) - 1 ] = '\0'; + strncat( ledger_path, ledger_config->name, sizeof(ledger_path) - strlen(ledger_path) - 1 ); + ledger_path[ sizeof(ledger_path) - 1 ] = '\0'; + + if( access( ledger_path, F_OK ) != 0 ) { + FD_LOG_NOTICE(( "Ledger directory does not exist: %s, attempting to download...", ledger_path )); + + char mkdir_cmd[2048]; + snprintf( mkdir_cmd, sizeof(mkdir_cmd), "mkdir -p %s", ledger_path ); + if( system( mkdir_cmd ) != 0 ) { + FD_LOG_ERR(( "Failed to create ledger directory: %s", ledger_path )); + return; + } + + char download_cmd[4096]; + snprintf( download_cmd, sizeof(download_cmd), + "gcloud storage cat gs://firedancer-ci-resources/%s.tar.gz | tar zxf - -C %s", + ledger_config->name, dump_dir ); + + FD_LOG_NOTICE(( "Downloading ledger from gcloud: %s", ledger_config->name )); + int download_result = system( download_cmd ); + + if( download_result != 0 ) { + FD_LOG_ERR(( "Failed to download ledger: %s", ledger_config->name )); + return; + } + + if( access( ledger_path, F_OK ) != 0 ) { + FD_LOG_ERR(( "Ledger directory still does not exist after download: %s", ledger_path )); + return; + } + + FD_LOG_NOTICE(( "Successfully downloaded and extracted ledger: %s", ledger_path )); + } + + if( chmod( ledger_path, 0700 ) != 0 ) { + FD_LOG_ERR(( "Failed to change permissions of ledger directory: %s", ledger_path )); + return; + } + + /* Set cluster version */ + strncpy( config->tiles.replay.cluster_version, ledger_config->cluster_version, + sizeof(config->tiles.replay.cluster_version) - 1 ); + config->tiles.replay.cluster_version[ sizeof(config->tiles.replay.cluster_version) - 1 ] = '\0'; + + /* Set funk configuration */ + config->firedancer.funk.heap_size_gib = ledger_config->funk_pages; + config->firedancer.funk.max_account_records = ledger_config->index_max; + + /* Set archiver configuration */ + config->tiles.archiver.enabled = 1; + config->tiles.archiver.end_slot = ledger_config->end_slot; + + strncpy( config->tiles.archiver.ingest_mode, "rocksdb", sizeof(config->tiles.archiver.ingest_mode) - 1 ); + config->tiles.archiver.ingest_mode[ sizeof(config->tiles.archiver.ingest_mode) - 1 ] = '\0'; + + strncpy( config->tiles.archiver.rocksdb_path, dump_dir, sizeof(config->tiles.archiver.rocksdb_path) - 1 ); + config->tiles.archiver.rocksdb_path[ sizeof(config->tiles.archiver.rocksdb_path) - 1 ] = '\0'; + strncat( config->tiles.archiver.rocksdb_path, "/", sizeof(config->tiles.archiver.rocksdb_path) - strlen(config->tiles.archiver.rocksdb_path) - 1 ); + config->tiles.archiver.rocksdb_path[ sizeof(config->tiles.archiver.rocksdb_path) - 1 ] = '\0'; + strncat( config->tiles.archiver.rocksdb_path, ledger_config->name, sizeof(config->tiles.archiver.rocksdb_path) - strlen(config->tiles.archiver.rocksdb_path) - 1 ); + config->tiles.archiver.rocksdb_path[ sizeof(config->tiles.archiver.rocksdb_path) - 1 ] = '\0'; + strncat( config->tiles.archiver.rocksdb_path, "/rocksdb", sizeof(config->tiles.archiver.rocksdb_path) - strlen(config->tiles.archiver.rocksdb_path) - 1 ); + config->tiles.archiver.rocksdb_path[ sizeof(config->tiles.archiver.rocksdb_path) - 1 ] = '\0'; + + // set paths to dump/ledger_config->name + strncpy( config->paths.snapshots, dump_dir, sizeof(config->paths.snapshots) - 1 ); + config->paths.snapshots[ sizeof(config->paths.snapshots) - 1 ] = '\0'; + strncat( config->paths.snapshots, "/", sizeof(config->paths.snapshots) - strlen(config->paths.snapshots) - 1 ); + config->paths.snapshots[ sizeof(config->paths.snapshots) - 1 ] = '\0'; + strncat( config->paths.snapshots, ledger_config->name, sizeof(config->paths.snapshots) - strlen(config->paths.snapshots) - 1 ); + config->paths.snapshots[ sizeof(config->paths.snapshots) - 1 ] = '\0'; + + /* Set snapshot configuration */ + config->firedancer.snapshots.incremental_snapshots = ledger_config->has_incremental; + config->firedancer.snapshots.sources.servers_cnt = 0; + config->firedancer.snapshots.sources.gossip.allow_any = false; + config->firedancer.snapshots.sources.gossip.allow_list_cnt = 0; + + /* Set gossip configuration based on genesis flag */ + if( ledger_config->genesis ) { + config->gossip.entrypoints_cnt = 0; /* No entrypoints for genesis mode */ + } else { + config->gossip.entrypoints_cnt = 1; + strncpy( config->gossip.entrypoints[0], "0.0.0.0:1", sizeof(config->gossip.entrypoints[0]) - 1 ); + config->gossip.entrypoints[0][ sizeof(config->gossip.entrypoints[0]) - 1 ] = '\0'; + } + + /* Set replay features if any */ + config->tiles.replay.enable_features_cnt = (uint)ledger_config->features_cnt; + for( ulong i = 0; i < ledger_config->features_cnt && i < FD_LEDGER_MAX_FEATURES; i++ ) { + strncpy( config->tiles.replay.enable_features[i], ledger_config->features[i], + sizeof(config->tiles.replay.enable_features[i]) - 1 ); + config->tiles.replay.enable_features[i][ sizeof(config->tiles.replay.enable_features[i]) - 1 ] = '\0'; + } + if( ledger_config->genesis ) { + strncpy( config->paths.genesis, dump_dir, sizeof(config->paths.genesis) - 1 ); + config->paths.genesis[ sizeof(config->paths.genesis) - 1 ] = '\0'; + strncat( config->paths.genesis, "/", sizeof(config->paths.genesis) - strlen(config->paths.genesis) - 1 ); + config->paths.genesis[ sizeof(config->paths.genesis) - 1 ] = '\0'; + strncat( config->paths.genesis, ledger_config->name, sizeof(config->paths.genesis) - strlen(config->paths.genesis) - 1 ); + config->paths.genesis[ sizeof(config->paths.genesis) - 1 ] = '\0'; + strncat( config->paths.genesis, "/", sizeof(config->paths.genesis) - strlen(config->paths.genesis) - 1 ); + config->paths.genesis[ sizeof(config->paths.genesis) - 1 ] = '\0'; + strncat( config->paths.genesis, "genesis.bin", sizeof(config->paths.genesis) - strlen(config->paths.genesis) - 1 ); + config->paths.genesis[ sizeof(config->paths.genesis) - 1 ] = '\0'; + } +} + +static void +backtest_cmd_fn( args_t * args, config_t * config ) { + /* Handle CI mode or running all ledgers */ + if( args->backtest.ci_mode || args->backtest.ledger_name[0] == '\0' ) { + if( args->backtest.ci_mode ) { + printf("Running CI ledgers one by one:\n"); + } else { + printf("Running all available ledgers one by one:\n"); + } + + /* Get the current executable path */ + char exe_path[1024]; + ssize_t len = readlink("/proc/self/exe", exe_path, sizeof(exe_path) - 1); + if( len == -1 ) { + fprintf(stderr, "Failed to get executable path\n"); + return; + } + exe_path[len] = '\0'; + + /* Choose which ledger set to use */ + const char* ledgers[FD_LEDGER_CONFIG_COUNT]; + ulong ledger_count; + if( args->backtest.ci_mode ) { + /* Use CI ledgers */ + ledger_count = FD_LEDGER_CI_CONFIG_COUNT; + for( ulong i=0; iname; + } else { + ledgers[i] = "unknown"; + } + } + } else { + /* Use all ledgers */ + ledger_count = FD_LEDGER_CONFIG_COUNT; + for( ulong i=0; iname; + } else { + ledgers[i] = "unknown"; + } + } + } + + ulong failed_count = 0; + + /* Start timing for CI mode */ + struct timespec ci_start_time, ci_end_time; + clock_gettime( CLOCK_MONOTONIC, &ci_start_time ); + + for( ulong i = 0; i < ledger_count; i++ ) { + printf("Running backtest %lu/%lu: %s\n", i + 1, ledger_count, ledgers[i]); + + /* Prepare arguments for the child process */ + char * child_argv[5]; + child_argv[0] = exe_path; + child_argv[1] = "backtest"; + child_argv[2] = (char *)ledgers[i]; + child_argv[3] = "--no-watch"; + child_argv[4] = NULL; + + /* Spawn child process */ + pid_t pid = fork(); + if( pid == 0 ) { + /* Child process */ + execv( exe_path, child_argv ); + fprintf(stderr, "Failed to exec backtest for ledger %s\n", ledgers[i]); + exit( 1 ); + } else if( pid > 0 ) { + /* Parent process - wait for child to complete */ + int status; + waitpid( pid, &status, 0 ); + if( WIFEXITED( status ) ) { + int exit_code = WEXITSTATUS( status ); + if( exit_code == 0 ) { + printf("✅ Backtest completed successfully for ledger: %s\n", ledgers[i]); + } else { + printf("❌ Backtest failed for ledger %s with exit code %d\n", ledgers[i], exit_code); + failed_count++; + } + } else { + printf("❌ Backtest process for ledger %s was terminated abnormally\n", ledgers[i]); + failed_count++; + } + } else { + printf("❌ Failed to fork process for ledger %s\n", ledgers[i]); + failed_count++; + } + } + + /* End timing for CI mode and display results */ + clock_gettime( CLOCK_MONOTONIC, &ci_end_time ); + + long elapsed_seconds = ci_end_time.tv_sec - ci_start_time.tv_sec; + long elapsed_nanoseconds = ci_end_time.tv_nsec - ci_start_time.tv_nsec; + + if( elapsed_nanoseconds < 0 ) { + elapsed_seconds--; + elapsed_nanoseconds += 1000000000L; + } + + double elapsed_seconds_double = (double)elapsed_seconds + (double)elapsed_nanoseconds / 1000000000.0; + + printf("⏱️ Backtest suite completed in %.3f seconds (%lu ledgers)\n", elapsed_seconds_double, ledger_count ); + + printf("Completed running all ledgers: %lu/%lu successful, %lu failed\n", + ledger_count - failed_count, ledger_count, failed_count); + + if( failed_count > 0 ) { + exit( 1 ); + } + return; + } + + /* Normal flow: run a specific ledger */ args_t c_args = configure_args(); configure_cmd_fn( &c_args, config ); + /* Create custom ledger configuration if flags are provided */ + create_custom_ledger_config( args ); + + /* Store ledger name in global variable for access in topo function */ + strncpy( g_ledger_name, args->backtest.ledger_name, sizeof(g_ledger_name) - 1 ); + g_ledger_name[ sizeof(g_ledger_name) - 1 ] = '\0'; + + /* Apply ledger configuration if provided */ + if( g_ledger_name[0] != '\0' && strcmp( g_ledger_name, "backtest" ) != 0 ) { + fd_ledger_config_t const * ledger_config = fd_ledger_config_find( g_ledger_name ); + if( !ledger_config ) { + if( g_has_custom_config ) { + FD_LOG_NOTICE(( "Using custom ledger configuration for: %s", g_ledger_name )); + apply_ledger_config( &g_custom_ledger_config, config ); + } else { + FD_LOG_ERR(( "Ledger configuration not found for: %s. Please provide a configuration flags.", g_ledger_name )); + return; + } + } else { + apply_ledger_config( ledger_config, config ); + } + } + initialize_workspaces( config ); initialize_stacks( config ); diff --git a/src/app/firedancer-dev/main.c b/src/app/firedancer-dev/main.c index 91681160cac..b664e5e96c6 100644 --- a/src/app/firedancer-dev/main.c +++ b/src/app/firedancer-dev/main.c @@ -5,6 +5,8 @@ #include "../shared/fd_action.h" #include "../shared/commands/configure/configure.h" +#include /* getenv */ + char const * FD_APP_NAME = "Firedancer"; char const * FD_BINARY_NAME = "firedancer-dev"; @@ -225,6 +227,11 @@ action_t * ACTIONS[] = { NULL, }; +extern void backtest_topo_initialize( config_t * config ); +extern void backtest_set_ledger_name( char const * ledger_name ); +extern void backtest_create_custom_config_from_args( int argc, char ** argv ); +extern void backtest_set_user_config_path( char const * config_path ); + int main( int argc, char ** argv ) { @@ -241,5 +248,49 @@ main( int argc, NULL }; - return fd_dev_main( argc, argv, 1, configs, fd_topo_initialize ); + /* Use backtest_topo_initialize if the backtest command is being used */ + void (* topo_init)( config_t * config ) = fd_topo_initialize; + if( argc > 1 && !strcmp( argv[1], "backtest" ) ) { + /* Check for --ci flag early - if present, use backtest_topo_initialize but skip config parsing */ + /* backtest_topo_initialize sets minimal config (archiver.ingest_mode) needed for topology init */ + int ci_mode = 0; + for( int i = 2; i < argc; i++ ) { + if( strcmp( argv[i], "--ci" ) == 0 ) { + ci_mode = 1; + break; + } + } + + /* Always use backtest_topo_initialize for backtest command to set minimal config */ + topo_init = backtest_topo_initialize; + + /* Parse --config flag early to capture user config path */ + /* This allows backtest_topo_initialize to reload TOML after applying ledger config */ + const char * user_config_path = NULL; + for( int i = 2; i < argc - 1; i++ ) { + if( strcmp( argv[i], "--config" ) == 0 ) { + user_config_path = argv[i + 1]; + break; + } + } + /* Also check environment variable */ + if( !user_config_path ) { + char * env_config = getenv( "FIREDANCER_CONFIG_TOML" ); + if( env_config ) { + user_config_path = env_config; + } + } + backtest_set_user_config_path( user_config_path ); + + if( !ci_mode ) { + /* Only parse config early if not in CI mode */ + /* In CI mode, backtest_cmd_fn will handle spawning child processes */ + /* Parse ledger name and custom config flags early (before fd_dev_main) */ + /* This ensures custom config is available when backtest_topo_initialize is called */ + backtest_create_custom_config_from_args( argc, argv ); + } + /* If ci_mode is set, skip early config parsing and let backtest_cmd_fn handle CI mode */ + } + + return fd_dev_main( argc, argv, 1, configs, topo_init ); } diff --git a/src/flamenco/runtime/tests/ledgers.h b/src/flamenco/runtime/tests/ledgers.h new file mode 100644 index 00000000000..250b1b37da0 --- /dev/null +++ b/src/flamenco/runtime/tests/ledgers.h @@ -0,0 +1,1235 @@ +#ifndef HEADER_fd_src_app_backtest_ledgers_h +#define HEADER_fd_src_app_backtest_ledgers_h + +#include "../../../util/fd_util_base.h" + +/* Maximum number of one-off features per ledger */ +#define FD_LEDGER_MAX_FEATURES (32UL) + +/* Maximum length of ledger name */ +#define FD_LEDGER_NAME_MAX_LEN (64UL) + +/* Maximum length of cluster version string */ +#define FD_LEDGER_CLUSTER_VERSION_MAX_LEN (16UL) + +/* Ledger test configuration structure */ +typedef struct fd_ledger_config { + char name[ FD_LEDGER_NAME_MAX_LEN ]; /* Ledger name (e.g., "mainnet-257066033-v2.3.0") */ + char cluster_version[ FD_LEDGER_CLUSTER_VERSION_MAX_LEN ]; /* Cluster version (e.g., "2.3.0") */ + + ulong funk_pages; /* Funk heap size in pages */ + ulong index_max; /* Maximum account records */ + ulong end_slot; /* End slot for replay */ + + int genesis; /* Whether to use genesis mode (1) or entrypoints (0) */ + int has_incremental; /* Whether incremental snapshots are enabled */ + + /* One-off features as a null-terminated array of strings */ + char features[ FD_LEDGER_MAX_FEATURES ][ 64UL ]; + ulong features_cnt; /* Number of features */ + +} fd_ledger_config_t; + +/* Individual ledger configurations */ +static const fd_ledger_config_t FD_LEDGER_TESTNET_519_V2_3_0 = { + .name = "testnet-519-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 255312007UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257066033_V2_3_0 = { + .name = "mainnet-257066033-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257066038UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257066844_V2_3_0 = { + .name = "mainnet-257066844-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257066849UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257067457_V2_3_0 = { + .name = "mainnet-257067457-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257067461UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257068890_V2_3_0 = { + .name = "mainnet-257068890-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257068895UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257181622_V2_3_0 = { + .name = "mainnet-257181622-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257181624UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_254462437_V2_3_0 = { + .name = "mainnet-254462437-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 16UL, + .index_max = 10000000UL, + .end_slot = 254462598UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_LOCAL_CLUSTER_V2_3_0 = { + .name = "local-cluster-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 1UL, + .index_max = 2000000UL, + .end_slot = 5010UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_262654839_V2_3_0 = { + .name = "mainnet-262654839-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 10000000UL, + .end_slot = 262654840UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257037451_V2_3_0 = { + .name = "mainnet-257037451-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257037454UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257035225_V2_3_0 = { + .name = "mainnet-257035225-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 257035233UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257465453_V2_3_0 = { + .name = "mainnet-257465453-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 10000000UL, + .end_slot = 257465454UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257058865_V2_3_0 = { + .name = "mainnet-257058865-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257058870UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257059815_V2_3_0 = { + .name = "mainnet-257059815-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257059818UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257061172_V2_3_0 = { + .name = "mainnet-257061172-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257061175UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257222682_V2_3_0 = { + .name = "mainnet-257222682-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257222688UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_264890264_V2_3_0 = { + .name = "mainnet-264890264-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 264890265UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257229353_V2_3_0 = { + .name = "mainnet-257229353-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 257229357UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257257983_V2_3_0 = { + .name = "mainnet-257257983-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257257986UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267728520_V2_3_0 = { + .name = "mainnet-267728520-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267728522UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267651942_V2_3_0 = { + .name = "mainnet-267651942-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267651943UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267081197_V2_3_0 = { + .name = "mainnet-267081197-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267081198UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267085604_V2_3_0 = { + .name = "mainnet-267085604-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267085605UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_265688706_V2_3_0 = { + .name = "mainnet-265688706-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 265688707UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_265330432_V2_3_0 = { + .name = "mainnet-265330432-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 265330433UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_268575190_V2_3_0 = { + .name = "mainnet-268575190-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 268575191UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_268129380_V2_3_0 = { + .name = "mainnet-268129380-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 268129380UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_268163043_V2_3_0 = { + .name = "mainnet-268163043-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 268163043UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_269511381_V2_3_0 = { + .name = "mainnet-269511381-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 269511381UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_269567236_V2_3_0 = { + .name = "mainnet-269567236-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 269567236UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_266134813_V2_3_0 = { + .name = "mainnet-266134813-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 266134814UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_266545736_V2_3_0 = { + .name = "mainnet-266545736-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 266545737UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267059180_V2_3_0 = { + .name = "mainnet-267059180-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267059181UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267580466_V2_3_0 = { + .name = "mainnet-267580466-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267580467UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_268196194_V2_3_0 = { + .name = "mainnet-268196194-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 268196195UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_267766641_V2_3_0 = { + .name = "mainnet-267766641-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 267766642UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_269648145_V2_3_0 = { + .name = "mainnet-269648145-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 269648146UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_281688085_V2_3_0 = { + .name = "testnet-281688085-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 281688086UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_277660422_V2_3_0 = { + .name = "mainnet-277660422-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 277660423UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_277876060_V2_3_0 = { + .name = "mainnet-277876060-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 277876061UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_277927063_V2_3_0 = { + .name = "mainnet-277927063-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 277927065UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_281375356_V2_3_0 = { + .name = "mainnet-281375356-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 281375359UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_251418170_V2_3_0 = { + .name = "mainnet-251418170-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 251418233UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_282232100_V2_3_0 = { + .name = "mainnet-282232100-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 282232101UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_282151715_V2_3_0 = { + .name = "mainnet-282151715-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 282151717UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_286450148_V2_3_0 = { + .name = "mainnet-286450148-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 286450151UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MULTI_EPOCH_PER_200_V2_3_0 = { + .name = "multi-epoch-per-200-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 1UL, + .index_max = 2000000UL, + .end_slot = 984UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MULTI_EPOCH_PER_300_V2_3_0 = { + .name = "multi-epoch-per-300-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 1UL, + .index_max = 2000000UL, + .end_slot = 984UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MULTI_EPOCH_PER_500_V2_3_0 = { + .name = "multi-epoch-per-500-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 1UL, + .index_max = 2000000UL, + .end_slot = 984UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_297489336_V2_3_0 = { + .name = "testnet-297489336-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 297489363UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_300377724_V2_3_0 = { + .name = "mainnet-300377724-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 300377728UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_300645644_V2_3_0 = { + .name = "mainnet-300645644-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 300645644UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_300648964_V2_3_0 = { + .name = "mainnet-300648964-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 300648964UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_301359740_V2_3_0 = { + .name = "mainnet-301359740-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 301359740UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257181032_V2_3_0 = { + .name = "mainnet-257181032-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257181035UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257047660_V2_3_0 = { + .name = "mainnet-257047660-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257047662UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_257047659_V2_3_0 = { + .name = "mainnet-257047659-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 257047660UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_308445707_V2_3_0 = { + .name = "mainnet-308445707-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 308445711UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_307395181_V2_3_0 = { + .name = "testnet-307395181-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 307395190UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_308392063_V2_3_0 = { + .name = "mainnet-308392063-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 308392090UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_DEVNET_350814254_V2_3_0 = { + .name = "devnet-350814254-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 350814284UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_311586340_V2_3_0 = { + .name = "testnet-311586340-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 311586380UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_281546597_V2_3_0 = { + .name = "testnet-281546597-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 281546597UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_324823213_V2_3_0 = { + .name = "mainnet-324823213-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 324823214UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_325467935_V2_3_0 = { + .name = "mainnet-325467935-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 325467936UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_283927487_V2_3_0 = { + .name = "testnet-283927487-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 283927497UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_321168308_V2_3_0 = { + .name = "testnet-321168308-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 321168308UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_327324660_V2_3_0 = { + .name = "mainnet-327324660-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 327324660UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_DEVNET_370199634_V2_3_0 = { + .name = "devnet-370199634-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 200000UL, + .end_slot = 370199634UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_330219081_V2_3_0 = { + .name = "mainnet-330219081-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 330219082UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_DEVNET_372721907_V2_3_0 = { + .name = "devnet-372721907-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 372721910UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_331691646_V2_3_0 = { + .name = "mainnet-331691646-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 4UL, + .index_max = 2000000UL, + .end_slot = 331691647UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_DEVNET_378683870_V2_3_0 = { + .name = "devnet-378683870-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 378683872UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_DEVNET_380592002_V2_3_0 = { + .name = "devnet-380592002-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 380592006UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_336218682_V2_3_0 = { + .name = "testnet-336218682-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 336218683UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_340269866_V2_3_0 = { + .name = "testnet-340269866-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 340269872UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +// TODO: Add this ledger +static const fd_ledger_config_t FD_LEDGER_TESTNET_340272018_V2_3_0 = { + .name = "testnet-340272018-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 340272024UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_DEVNET_390056400_V2_3_0 = { + .name = "devnet-390056400-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 10UL, + .index_max = 2000000UL, + .end_slot = 390056406UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_346556000 = { + .name = "testnet-346556000", + .cluster_version = "2.3.0", + .funk_pages = 3UL, + .index_max = 2000000UL, + .end_slot = 346556337UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_346179946 = { + .name = "testnet-346179946", + .cluster_version = "2.3.0", + .funk_pages = 30UL, + .index_max = 90000000UL, + .end_slot = 346179950UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MULTI_BPF_LOADER_V2_3_0 = { + .name = "multi-bpf-loader-v2.3.0", + .cluster_version = "2.3.0", + .funk_pages = 1UL, + .index_max = 1000UL, + .end_slot = 108UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_LOCAL_MULTI_BOUNDARY = { + .name = "local-multi-boundary", + .cluster_version = "2.3.0", + .funk_pages = 1UL, + .index_max = 1000UL, + .end_slot = 2325UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_GENESIS_V3_0 = { + .name = "genesis-v3.0", + .cluster_version = "3.0.0", + .funk_pages = 1UL, + .index_max = 3000UL, + .end_slot = 1280UL, + .genesis = 1, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_LOCALNET_STAKE_V3_0_0 = { + .name = "localnet-stake-v3.0.0", + .cluster_version = "3.0.0", + .funk_pages = 1UL, + .index_max = 3000UL, + .end_slot = 541UL, + .genesis = 0, + .has_incremental = 0, + .features = { "" }, + .features_cnt = 0UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_368528500_STRICTER_ABI = { + .name = "mainnet-368528500-stricter-abi", + .cluster_version = "3.0.3", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 368528527UL, + .genesis = 0, + .has_incremental = 0, + .features = { "CxeBn9PVeeXbmjbNwLv6U4C6svNxnC4JX6mfkvgeMocM" }, + .features_cnt = 1UL, +}; + +static const fd_ledger_config_t FD_LEDGER_MAINNET_368528500_DIRECT_MAPPING = { + .name = "mainnet-368528500-direct-mapping", + .cluster_version = "3.0.3", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 368528527UL, + .genesis = 0, + .has_incremental = 0, + .features = { "CxeBn9PVeeXbmjbNwLv6U4C6svNxnC4JX6mfkvgeMocM", "9s3RKimHWS44rJcJ9P1rwCmn2TvMqtZQBmz815ZUUHqJ" }, + .features_cnt = 2UL, +}; + +static const fd_ledger_config_t FD_LEDGER_TESTNET_362107883_DIRECT_MAPPING_2 = { + .name = "testnet-362107883-direct-mapping-2", + .cluster_version = "3.0.3", + .funk_pages = 5UL, + .index_max = 2000000UL, + .end_slot = 362219427UL, + .genesis = 0, + .has_incremental = 0, + .features = { "CxeBn9PVeeXbmjbNwLv6U4C6svNxnC4JX6mfkvgeMocM", "9s3RKimHWS44rJcJ9P1rwCmn2TvMqtZQBmz815ZUUHqJ" }, + .features_cnt = 2UL, +}; + +/* Array of all ledger configurations for CI testing */ +#define ALL_LEDGERS \ + &FD_LEDGER_TESTNET_519_V2_3_0, \ + &FD_LEDGER_MAINNET_257066033_V2_3_0, \ + &FD_LEDGER_MAINNET_257066844_V2_3_0, \ + &FD_LEDGER_MAINNET_257067457_V2_3_0, \ + &FD_LEDGER_MAINNET_257068890_V2_3_0, \ + &FD_LEDGER_MAINNET_257181622_V2_3_0, \ + &FD_LEDGER_MAINNET_254462437_V2_3_0, \ + &FD_LEDGER_LOCAL_CLUSTER_V2_3_0, \ + &FD_LEDGER_MAINNET_262654839_V2_3_0, \ + &FD_LEDGER_MAINNET_257037451_V2_3_0, \ + &FD_LEDGER_MAINNET_257035225_V2_3_0, \ + &FD_LEDGER_MAINNET_257465453_V2_3_0, \ + &FD_LEDGER_MAINNET_257058865_V2_3_0, \ + &FD_LEDGER_MAINNET_257059815_V2_3_0, \ + &FD_LEDGER_MAINNET_257061172_V2_3_0, \ + &FD_LEDGER_MAINNET_257222682_V2_3_0, \ + &FD_LEDGER_MAINNET_264890264_V2_3_0, \ + &FD_LEDGER_MAINNET_257229353_V2_3_0, \ + &FD_LEDGER_MAINNET_257257983_V2_3_0, \ + &FD_LEDGER_MAINNET_267728520_V2_3_0, \ + &FD_LEDGER_MAINNET_267651942_V2_3_0, \ + &FD_LEDGER_MAINNET_267081197_V2_3_0, \ + &FD_LEDGER_MAINNET_267085604_V2_3_0, \ + &FD_LEDGER_MAINNET_265688706_V2_3_0, \ + &FD_LEDGER_MAINNET_265330432_V2_3_0, \ + &FD_LEDGER_MAINNET_268575190_V2_3_0, \ + &FD_LEDGER_MAINNET_268129380_V2_3_0, \ + &FD_LEDGER_MAINNET_268163043_V2_3_0, \ + &FD_LEDGER_MAINNET_269511381_V2_3_0, \ + &FD_LEDGER_MAINNET_269567236_V2_3_0, \ + &FD_LEDGER_MAINNET_266134813_V2_3_0, \ + &FD_LEDGER_MAINNET_266545736_V2_3_0, \ + &FD_LEDGER_MAINNET_267059180_V2_3_0, \ + &FD_LEDGER_MAINNET_267580466_V2_3_0, \ + &FD_LEDGER_MAINNET_268196194_V2_3_0, \ + &FD_LEDGER_MAINNET_267766641_V2_3_0, \ + &FD_LEDGER_MAINNET_269648145_V2_3_0, \ + &FD_LEDGER_TESTNET_281688085_V2_3_0, \ + &FD_LEDGER_MAINNET_277660422_V2_3_0, \ + &FD_LEDGER_MAINNET_277876060_V2_3_0, \ + &FD_LEDGER_MAINNET_277927063_V2_3_0, \ + &FD_LEDGER_MAINNET_281375356_V2_3_0, \ + &FD_LEDGER_MAINNET_251418170_V2_3_0, \ + &FD_LEDGER_MAINNET_282232100_V2_3_0, \ + &FD_LEDGER_MAINNET_282151715_V2_3_0, \ + &FD_LEDGER_MAINNET_286450148_V2_3_0, \ + &FD_LEDGER_MULTI_EPOCH_PER_200_V2_3_0, \ + &FD_LEDGER_MULTI_EPOCH_PER_300_V2_3_0, \ + &FD_LEDGER_MULTI_EPOCH_PER_500_V2_3_0, \ + &FD_LEDGER_TESTNET_297489336_V2_3_0, \ + &FD_LEDGER_MAINNET_300377724_V2_3_0, \ + &FD_LEDGER_MAINNET_300645644_V2_3_0, \ + &FD_LEDGER_MAINNET_300648964_V2_3_0, \ + &FD_LEDGER_MAINNET_301359740_V2_3_0, \ + &FD_LEDGER_MAINNET_257181032_V2_3_0, \ + &FD_LEDGER_MAINNET_257047660_V2_3_0, \ + &FD_LEDGER_MAINNET_257047659_V2_3_0, \ + &FD_LEDGER_MAINNET_308445707_V2_3_0, \ + &FD_LEDGER_TESTNET_307395181_V2_3_0, \ + &FD_LEDGER_MAINNET_308392063_V2_3_0, \ + &FD_LEDGER_DEVNET_350814254_V2_3_0, \ + &FD_LEDGER_TESTNET_311586340_V2_3_0, \ + &FD_LEDGER_TESTNET_281546597_V2_3_0, \ + &FD_LEDGER_MAINNET_324823213_V2_3_0, \ + &FD_LEDGER_MAINNET_325467935_V2_3_0, \ + &FD_LEDGER_TESTNET_283927487_V2_3_0, \ + &FD_LEDGER_TESTNET_321168308_V2_3_0, \ + &FD_LEDGER_MAINNET_327324660_V2_3_0, \ + &FD_LEDGER_DEVNET_370199634_V2_3_0, \ + &FD_LEDGER_MAINNET_330219081_V2_3_0, \ + &FD_LEDGER_DEVNET_372721907_V2_3_0, \ + &FD_LEDGER_MAINNET_331691646_V2_3_0, \ + &FD_LEDGER_DEVNET_378683870_V2_3_0, \ + &FD_LEDGER_DEVNET_380592002_V2_3_0, \ + &FD_LEDGER_TESTNET_336218682_V2_3_0, \ + &FD_LEDGER_TESTNET_340269866_V2_3_0, \ + &FD_LEDGER_DEVNET_390056400_V2_3_0, \ + &FD_LEDGER_TESTNET_346556000, \ + &FD_LEDGER_TESTNET_346179946, \ + &FD_LEDGER_MULTI_BPF_LOADER_V2_3_0, \ + &FD_LEDGER_LOCAL_MULTI_BOUNDARY, \ + &FD_LEDGER_GENESIS_V3_0, \ + &FD_LEDGER_LOCALNET_STAKE_V3_0_0, \ + &FD_LEDGER_MAINNET_368528500_STRICTER_ABI, \ + &FD_LEDGER_MAINNET_368528500_DIRECT_MAPPING, \ + &FD_LEDGER_TESTNET_362107883_DIRECT_MAPPING_2 + + +/* Array of ledger configurations specifically for CI testing (from run_backtest_ci.sh) */ +#define CI_LEDGERS \ + &FD_LEDGER_MAINNET_308392063_V2_3_0, \ + &FD_LEDGER_DEVNET_350814254_V2_3_0, \ + &FD_LEDGER_TESTNET_281546597_V2_3_0, \ + &FD_LEDGER_MAINNET_324823213_V2_3_0, \ + &FD_LEDGER_MAINNET_325467935_V2_3_0, \ + &FD_LEDGER_TESTNET_283927487_V2_3_0, \ + &FD_LEDGER_TESTNET_321168308_V2_3_0, \ + &FD_LEDGER_MAINNET_327324660_V2_3_0, \ + &FD_LEDGER_DEVNET_370199634_V2_3_0, \ + &FD_LEDGER_DEVNET_378683870_V2_3_0, \ + &FD_LEDGER_MAINNET_330219081_V2_3_0, \ + &FD_LEDGER_DEVNET_372721907_V2_3_0, \ + &FD_LEDGER_MAINNET_331691646_V2_3_0, \ + &FD_LEDGER_TESTNET_336218682_V2_3_0, \ + &FD_LEDGER_TESTNET_340269866_V2_3_0, \ + &FD_LEDGER_DEVNET_390056400_V2_3_0, \ + &FD_LEDGER_MAINNET_254462437_V2_3_0, \ + &FD_LEDGER_MULTI_EPOCH_PER_200_V2_3_0, \ + &FD_LEDGER_TESTNET_346556000, \ + &FD_LEDGER_MULTI_BPF_LOADER_V2_3_0, \ + &FD_LEDGER_DEVNET_380592002_V2_3_0, \ + &FD_LEDGER_LOCAL_MULTI_BOUNDARY, \ + &FD_LEDGER_GENESIS_V3_0, \ + &FD_LEDGER_LOCALNET_STAKE_V3_0_0, \ + &FD_LEDGER_MAINNET_368528500_STRICTER_ABI, \ + &FD_LEDGER_MAINNET_368528500_DIRECT_MAPPING, \ + &FD_LEDGER_TESTNET_362107883_DIRECT_MAPPING_2 + +/* Total number of ledger configurations */ +#define FD_LEDGER_CONFIG_COUNT (86UL) + +/* Total number of CI ledger configurations */ +#define FD_LEDGER_CI_CONFIG_COUNT (27UL) + +/* Array declaration for easy iteration */ +static const fd_ledger_config_t * const fd_ledger_configs[ FD_LEDGER_CONFIG_COUNT + 1UL ] = { + ALL_LEDGERS, + NULL +}; + +/* Array declaration for CI ledger iteration */ +static const fd_ledger_config_t * const fd_ledgers_ci_configs[ FD_LEDGER_CI_CONFIG_COUNT + 1UL ] = { + CI_LEDGERS, + NULL +}; + +/* Helper function to find a ledger configuration by name */ +static inline fd_ledger_config_t const * +fd_ledger_config_find( char const * name ) { + for( ulong i = 0UL; i < FD_LEDGER_CONFIG_COUNT; i++ ) { + if( !strcmp( fd_ledger_configs[ i ]->name, name ) ) { + return fd_ledger_configs[ i ]; + } + } + return NULL; +} + +/* Helper function to get ledger configuration by index */ +static inline fd_ledger_config_t const * +fd_ledger_config_get( ulong idx ) { + if( FD_UNLIKELY( idx >= FD_LEDGER_CONFIG_COUNT ) ) return NULL; + return fd_ledger_configs[ idx ]; +} + +#endif /* HEADER_fd_src_app_backtest_ledgers_h */