LCOV - code coverage report
Current view: top level - flamenco/genesis - fd_genesis_create.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 256 276 92.8 %
Date: 2026-06-29 05:51:35 Functions: 8 8 100.0 %

          Line data    Source code
       1             : #include "fd_genesis_create.h"
       2             : 
       3             : #include "../runtime/fd_system_ids.h"
       4             : #include "../stakes/fd_stakes.h"
       5             : #include "../runtime/program/fd_vote_program.h"
       6             : #include "../runtime/program/vote/fd_vote_codec.h"
       7             : #include "../runtime/sysvar/fd_sysvar_rent.h"
       8             : 
       9             : /* TODO: Unify type with the one in fd_genesis_parse.c */
      10             : 
      11             : struct fd_rust_duration {
      12             :   ulong seconds;
      13             :   uint nanoseconds;
      14             : };
      15             : typedef struct fd_rust_duration fd_rust_duration_t;
      16             : 
      17             : struct fd_poh_config {
      18             :   fd_rust_duration_t target_tick_duration;
      19             :   ulong target_tick_count;
      20             :   uchar has_target_tick_count;
      21             :   ulong hashes_per_tick;
      22             :   uchar has_hashes_per_tick;
      23             : };
      24             : typedef struct fd_poh_config fd_poh_config_t;
      25             : 
      26             : struct fd_genesis_account {
      27             :   ulong       lamports;
      28             :   ulong       data_len;
      29             :   uchar *     data;
      30             :   fd_pubkey_t owner;
      31             :   uchar       executable;
      32             :   ulong       rent_epoch;
      33             : };
      34             : typedef struct fd_genesis_account fd_genesis_account_t;
      35             : 
      36             : struct fd_genesis_account_pair {
      37             :   fd_pubkey_t          key;
      38             :   fd_genesis_account_t account;
      39             : };
      40             : typedef struct fd_genesis_account_pair fd_genesis_account_pair_t;
      41             : 
      42             : #define SORT_NAME sort_acct
      43        1014 : #define SORT_KEY_T fd_genesis_account_pair_t
      44         825 : #define SORT_BEFORE(a,b) (0>memcmp( (a).key.ul, (b).key.ul, sizeof(fd_pubkey_t) ))
      45             : #include "../../util/tmpl/fd_sort.c"
      46             : 
      47             : static inline uchar *
      48         252 : emit_u8( uchar * p, uchar * end, uchar v ) {
      49         252 :   if( FD_UNLIKELY( p+1>end ) ) return NULL;
      50         252 :   *p = v;
      51         252 :   return p+1;
      52         252 : }
      53             : 
      54             : static inline uchar *
      55          24 : emit_u32( uchar * p, uchar * end, uint v ) {
      56          24 :   if( FD_UNLIKELY( p+4>end ) ) return NULL;
      57          24 :   FD_STORE( uint, p, v );
      58          24 :   return p+4;
      59          24 : }
      60             : 
      61             : static inline uchar *
      62         783 : emit_u64( uchar * p, uchar * end, ulong v ) {
      63         783 :   if( FD_UNLIKELY( p+8>end ) ) return NULL;
      64         780 :   FD_STORE( ulong, p, v );
      65         780 :   return p+8;
      66         783 : }
      67             : 
      68             : static inline uchar *
      69          84 : emit_f64( uchar * p, uchar * end, double v ) {
      70          84 :   if( FD_UNLIKELY( p+8>end ) ) return NULL;
      71          84 :   FD_STORE( double, p, v );
      72          84 :   return p+8;
      73          84 : }
      74             : 
      75             : static inline uchar *
      76         408 : emit_bytes( uchar * p, uchar * end, void const * src, ulong n ) {
      77         408 :   if( FD_UNLIKELY( p+n>end ) ) return NULL;
      78         408 :   fd_memcpy( p, src, n );
      79         408 :   return p+n;
      80         408 : }
      81             : 
      82             : /* Private struct mirroring the Solana GenesisConfig bincode layout.
      83             :    Only used locally for building up state before serialization. */
      84             : 
      85             : struct genesis_solana {
      86             :   ulong                      creation_time;
      87             :   ulong                      accounts_len;
      88             :   fd_genesis_account_pair_t * accounts;
      89             :   ulong                      native_instruction_processors_len;
      90             :   ulong                      rewards_pools_len;
      91             :   ulong                      ticks_per_slot;
      92             :   ulong                      unused;
      93             :   fd_poh_config_t            poh_config;
      94             :   ulong                      __backwards_compat_with_v0_23;
      95             :   fd_fee_rate_governor_t     fee_rate_governor;
      96             :   fd_rent_t                  rent;
      97             :   fd_inflation_t             inflation;
      98             :   fd_epoch_schedule_t        epoch_schedule;
      99             :   uint                       cluster_type;
     100             : };
     101             : typedef struct genesis_solana genesis_solana_t;
     102             : 
     103             : /* genesis_encode serializes a genesis_solana_t into a bincode blob
     104             :    byte-for-byte compatible with Anza's genesis.bin format.  Returns the
     105             :    number of bytes written, or 0 on failure (buffer too small). */
     106             : 
     107             : static ulong
     108             : genesis_encode( genesis_solana_t const * g,
     109             :                 uchar *                  buf,
     110          15 :                 ulong                    bufsz ) {
     111          15 :   uchar * p   = buf;
     112          15 :   uchar * end = buf + bufsz;
     113             : 
     114        1551 : # define EMIT(expr) do { p = (expr); if( FD_UNLIKELY( !p ) ) return 0UL; } while(0)
     115             : 
     116          15 :   EMIT( emit_u64( p, end, g->creation_time ) );
     117             : 
     118             :   /* accounts vector */
     119          12 :   EMIT( emit_u64( p, end, g->accounts_len ) );
     120         204 :   for( ulong i=0; i<g->accounts_len; i++ ) {
     121         192 :     fd_genesis_account_pair_t const * a = &g->accounts[i];
     122         192 :     EMIT( emit_bytes( p, end, a->key.key, 32 ) );
     123         192 :     EMIT( emit_u64(   p, end, a->account.lamports ) );
     124         192 :     EMIT( emit_u64(   p, end, a->account.data_len ) );
     125         192 :     if( a->account.data_len )
     126          24 :       EMIT( emit_bytes( p, end, a->account.data, a->account.data_len ) );
     127         192 :     EMIT( emit_bytes( p, end, a->account.owner.key, 32 ) );
     128         192 :     EMIT( emit_u8(    p, end, !!a->account.executable ) );
     129         192 :     EMIT( emit_u64(   p, end, a->account.rent_epoch ) );
     130         192 :   }
     131             : 
     132             :   /* native_instruction_processors vector
     133             :      TODO: currently always empty */
     134          12 :   EMIT( emit_u64( p, end, g->native_instruction_processors_len ) );
     135             : 
     136             :   /* rewards_pools vector
     137             :      TODO: currently always empty */
     138          12 :   EMIT( emit_u64( p, end, g->rewards_pools_len ) );
     139             : 
     140          12 :   EMIT( emit_u64( p, end, g->ticks_per_slot ) );
     141          12 :   EMIT( emit_u64( p, end, g->unused ) );
     142             : 
     143             :   /* poh_config
     144             :      TODO: has target tick count always == 0 */
     145          12 :   EMIT( emit_u64( p, end, g->poh_config.target_tick_duration.seconds ) );
     146          12 :   EMIT( emit_u32( p, end, g->poh_config.target_tick_duration.nanoseconds ) );
     147          12 :   EMIT( emit_u8(  p, end, !!g->poh_config.has_target_tick_count ) );
     148          12 :   if( g->poh_config.has_target_tick_count )
     149           0 :     EMIT( emit_u64( p, end, g->poh_config.target_tick_count ) );
     150          12 :   EMIT( emit_u8(  p, end, !!g->poh_config.has_hashes_per_tick ) );
     151          12 :   if( g->poh_config.has_hashes_per_tick )
     152           0 :     EMIT( emit_u64( p, end, g->poh_config.hashes_per_tick ) );
     153             : 
     154             :   /* TODO: always set to 0 */
     155          12 :   EMIT( emit_u64( p, end, g->__backwards_compat_with_v0_23 ) );
     156             : 
     157             :   /* fee_rate_governor */
     158          12 :   EMIT( emit_u64( p, end, g->fee_rate_governor.target_lamports_per_signature ) );
     159          12 :   EMIT( emit_u64( p, end, g->fee_rate_governor.target_signatures_per_slot ) );
     160          12 :   EMIT( emit_u64( p, end, g->fee_rate_governor.min_lamports_per_signature ) );
     161          12 :   EMIT( emit_u64( p, end, g->fee_rate_governor.max_lamports_per_signature ) );
     162          12 :   EMIT( emit_u8(  p, end, g->fee_rate_governor.burn_percent ) );
     163             : 
     164             :   /* rent */
     165          12 :   EMIT( emit_u64( p, end, g->rent.lamports_per_uint8_year ) );
     166          12 :   EMIT( emit_f64( p, end, g->rent.exemption_threshold ) );
     167          12 :   EMIT( emit_u8(  p, end, g->rent.burn_percent ) );
     168             : 
     169             :   /* inflation */
     170          12 :   EMIT( emit_f64( p, end, g->inflation.initial ) );
     171          12 :   EMIT( emit_f64( p, end, g->inflation.terminal ) );
     172          12 :   EMIT( emit_f64( p, end, g->inflation.taper ) );
     173          12 :   EMIT( emit_f64( p, end, g->inflation.foundation ) );
     174          12 :   EMIT( emit_f64( p, end, g->inflation.foundation_term ) );
     175          12 :   EMIT( emit_f64( p, end, g->inflation.unused ) );
     176             : 
     177             :   /* epoch_schedule */
     178          12 :   EMIT( emit_u64( p, end, g->epoch_schedule.slots_per_epoch ) );
     179          12 :   EMIT( emit_u64( p, end, g->epoch_schedule.leader_schedule_slot_offset ) );
     180          12 :   EMIT( emit_u8(  p, end, !!g->epoch_schedule.warmup ) );
     181          12 :   EMIT( emit_u64( p, end, g->epoch_schedule.first_normal_epoch ) );
     182          12 :   EMIT( emit_u64( p, end, g->epoch_schedule.first_normal_slot ) );
     183             : 
     184          12 :   EMIT( emit_u32( p, end, g->cluster_type ) );
     185             : 
     186          12 : # undef EMIT
     187          12 :   return (ulong)(p - buf);
     188          12 : }
     189             : 
     190             : static ulong
     191             : genesis_create( void *                       buf,
     192             :                 ulong                        bufsz,
     193          15 :                 fd_genesis_options_t const * options ) {
     194             : 
     195          15 : # define REQUIRE(c)                         \
     196          45 :   do {                                      \
     197          45 :     if( FD_UNLIKELY( !(c) ) ) {             \
     198           0 :       FD_LOG_WARNING(( "FAIL: %s", #c ));   \
     199           0 :       return 0UL;                           \
     200           0 :     }                                       \
     201          45 :   } while(0);
     202             : 
     203          15 :   genesis_solana_t genesis[1] = {0};
     204             : 
     205          15 :   genesis->cluster_type = 3;  /* development */
     206             : 
     207          15 :   genesis->creation_time  = options->creation_time;
     208          15 :   genesis->ticks_per_slot = options->ticks_per_slot;
     209          15 :   REQUIRE( genesis->ticks_per_slot );
     210             : 
     211          15 :   genesis->unused = 1024UL; /* match Anza genesis byte-for-byte */
     212             : 
     213          15 :   genesis->poh_config.has_hashes_per_tick = !!options->hashes_per_tick;
     214          15 :   genesis->poh_config.hashes_per_tick     =   options->hashes_per_tick;
     215             : 
     216          15 :   ulong target_tick_micros = options->target_tick_duration_micros;
     217          15 :   REQUIRE( target_tick_micros );
     218          15 :   genesis->poh_config.target_tick_duration = (fd_rust_duration_t) {
     219          15 :     .seconds     =         target_tick_micros / 1000000UL,
     220          15 :     .nanoseconds = (uint)( target_tick_micros % 1000000UL * 1000UL ),
     221          15 :   };
     222             : 
     223             :   /* Create fee rate governor */
     224             : 
     225          15 :   genesis->fee_rate_governor = (fd_fee_rate_governor_t) {
     226          15 :     .target_lamports_per_signature  =  10000UL,
     227          15 :     .target_signatures_per_slot     =  20000UL,
     228          15 :     .min_lamports_per_signature     =   5000UL,
     229          15 :     .max_lamports_per_signature     = 100000UL,
     230          15 :     .burn_percent                   =     50,
     231          15 :   };
     232             : 
     233             :   /* Create rent configuration */
     234             : 
     235          15 :   genesis->rent = (fd_rent_t) {
     236          15 :     .lamports_per_uint8_year = 3480,
     237          15 :     .exemption_threshold     = 2.0,
     238          15 :     .burn_percent            = 50,
     239          15 :   };
     240             : 
     241             :   /* Create inflation configuration */
     242             : 
     243          15 :   genesis->inflation = (fd_inflation_t) {
     244          15 :     .initial         = 0.08,
     245          15 :     .terminal        = 0.015,
     246          15 :     .taper           = 0.15,
     247          15 :     .foundation      = 0.05,
     248          15 :     .foundation_term = 7.0,
     249          15 :   };
     250             : 
     251             :   /* Create epoch schedule */
     252             :   /* TODO The epoch schedule should be configurable! */
     253             : 
     254             :   /* If warmup is enabled:
     255             :      MINIMUM_SLOTS_PER_EPOCH = 32
     256             :      first_normal_epoch = log2( slots_per_epoch ) - log2( MINIMUM_SLOTS_PER_EPOCH  )
     257             :      first_normal_slot  = MINIMUM_SLOTS_PER_EPOCH * ( 2^( first_normal_epoch ) - 1 )
     258             :   */
     259             : 
     260          15 :   genesis->epoch_schedule = (fd_epoch_schedule_t) {
     261          15 :     .slots_per_epoch             = 8192UL,
     262          15 :     .leader_schedule_slot_offset = 8192UL,
     263          15 :     .warmup                      = fd_uchar_if( options->warmup_epochs,    1,   0   ),
     264          15 :     .first_normal_epoch          = fd_ulong_if( options->warmup_epochs,    8UL, 0UL ),
     265          15 :     .first_normal_slot           = fd_ulong_if( options->warmup_epochs, 8160UL, 0UL ),
     266          15 :   };
     267             : 
     268             :   /* Create faucet account */
     269             : 
     270          15 :   fd_genesis_account_pair_t const faucet_account = {
     271          15 :     .key = options->faucet_pubkey,
     272          15 :     .account = {
     273          15 :       .lamports   = options->faucet_balance,
     274          15 :       .owner      = fd_solana_system_program_id
     275          15 :     }
     276          15 :   };
     277          15 :   ulong const faucet_account_index = genesis->accounts_len++;
     278             : 
     279             :   /* Create identity account (vote authority, withdraw authority) */
     280             : 
     281          15 :   fd_genesis_account_pair_t const identity_account = {
     282          15 :     .key = options->identity_pubkey,
     283          15 :     .account = {
     284          15 :       .lamports   = 500000000000UL /* 500 SOL */,
     285          15 :       .owner      = fd_solana_system_program_id
     286          15 :     }
     287          15 :   };
     288          15 :   ulong const identity_account_index = genesis->accounts_len++;
     289             : 
     290             :   /* Create vote account */
     291             : 
     292          15 :   ulong const vote_account_index = genesis->accounts_len++;
     293             : 
     294          15 :   uchar vote_state_data[ FD_VOTE_STATE_V3_SZ ] = {0};
     295             : 
     296          15 :   FD_SCRATCH_SCOPE_BEGIN {
     297          15 :     fd_vote_state_versioned_t versioned[1];
     298          15 :     fd_vote_state_versioned_new( versioned, fd_vote_state_versioned_enum_v3 );
     299             : 
     300          15 :     fd_vote_state_v3_t * vote_state   = &versioned->v3;
     301          15 :     vote_state->node_pubkey           = options->identity_pubkey;
     302          15 :     vote_state->authorized_withdrawer = options->identity_pubkey;
     303          15 :     vote_state->commission            = 100;
     304             : 
     305          15 :     fd_vote_authorized_voter_t * voter = fd_vote_authorized_voters_pool_ele_acquire( vote_state->authorized_voters.pool );
     306          15 :     *voter = (fd_vote_authorized_voter_t) {
     307          15 :       .epoch  = 0UL,
     308          15 :       .pubkey = options->identity_pubkey,
     309          15 :       .prio   = options->identity_pubkey.uc[0],
     310          15 :     };
     311          15 :     fd_vote_authorized_voters_treap_ele_insert( vote_state->authorized_voters.treap, voter, vote_state->authorized_voters.pool );
     312             : 
     313          15 :     REQUIRE( !fd_vote_state_versioned_serialize( versioned, vote_state_data, sizeof(vote_state_data) ) );
     314          15 :   }
     315          15 :   FD_SCRATCH_SCOPE_END;
     316             : 
     317             :   /* Create stake account */
     318             : 
     319          15 :   ulong const stake_account_index = genesis->accounts_len++;
     320             : 
     321          15 :   uchar stake_data[ FD_STAKE_STATE_SZ ] = {0};
     322             : 
     323          15 :   ulong stake_state_min_bal = fd_rent_exempt_minimum_balance( &genesis->rent, FD_STAKE_STATE_SZ   );
     324          15 :   ulong vote_min_bal        = fd_rent_exempt_minimum_balance( &genesis->rent, FD_VOTE_STATE_V3_SZ );
     325             : 
     326          15 :   do {
     327          15 :     FD_STORE( fd_stake_state_t, stake_data, ((fd_stake_state_t) {
     328          15 :       .stake_type = FD_STAKE_STATE_STAKE,
     329          15 :       .stake = {
     330          15 :         .meta = {
     331          15 :           .rent_exempt_reserve = stake_state_min_bal,
     332          15 :           .staker              = options->identity_pubkey,
     333          15 :           .withdrawer          = options->identity_pubkey,
     334          15 :         },
     335          15 :         .stake = (fd_stake_t) {
     336          15 :           .delegation = (fd_delegation_t) {
     337          15 :             .voter_pubkey         = options->vote_pubkey,
     338          15 :             .stake                = fd_ulong_max( stake_state_min_bal, options->vote_account_stake ),
     339          15 :             .activation_epoch     = ULONG_MAX, /* bootstrap stake denoted with ULONG_MAX */
     340          15 :             .deactivation_epoch   = ULONG_MAX,
     341          15 :             .warmup_cooldown_rate = 0.25
     342          15 :           },
     343          15 :           .credits_observed = 0UL
     344          15 :         }
     345          15 :       }
     346          15 :     }) );
     347          15 :   } while(0);
     348             : 
     349             :   /* Read enabled features */
     350             : 
     351          15 :   ulong         feature_cnt = 0UL;
     352          15 :   fd_pubkey_t * features =
     353          15 :       fd_scratch_alloc( alignof(fd_pubkey_t), FD_FEATURE_ID_CNT * sizeof(fd_pubkey_t) );
     354             : 
     355          15 :   if( options->features ) {
     356           6 :     for( fd_feature_id_t const * id = fd_feature_iter_init();
     357        1668 :                                      !fd_feature_iter_done( id );
     358        1662 :                                  id = fd_feature_iter_next( id ) ) {
     359        1662 :       if( fd_features_get( options->features, id ) == 0UL )
     360           0 :         features[ feature_cnt++ ] = id->id;
     361        1662 :     }
     362           6 :   }
     363             : 
     364             :   /* Allocate the account table */
     365             : 
     366          15 :   ulong default_funded_cnt = options->fund_initial_accounts;
     367             : 
     368          15 :   ulong default_funded_idx = genesis->accounts_len;      genesis->accounts_len += default_funded_cnt;
     369          15 :   ulong feature_gate_idx   = genesis->accounts_len;      genesis->accounts_len += feature_cnt;
     370             : 
     371          15 :   genesis->accounts = fd_scratch_alloc( alignof(fd_genesis_account_pair_t),
     372          15 :                                         genesis->accounts_len * sizeof(fd_genesis_account_pair_t) );
     373          15 :   fd_memset( genesis->accounts, 0,      genesis->accounts_len * sizeof(fd_genesis_account_pair_t) );
     374             : 
     375          15 :   genesis->accounts[ faucet_account_index ] = faucet_account;
     376          15 :   genesis->accounts[ identity_account_index ] = identity_account;
     377          15 :   genesis->accounts[ stake_account_index ] = (fd_genesis_account_pair_t) {
     378          15 :     .key     = options->stake_pubkey,
     379          15 :     .account = (fd_genesis_account_t) {
     380          15 :       .lamports   = fd_ulong_max( stake_state_min_bal, options->vote_account_stake ),
     381          15 :       .data_len   = FD_STAKE_STATE_SZ,
     382          15 :       .data       = stake_data,
     383          15 :       .owner      = fd_solana_stake_program_id
     384          15 :     }
     385          15 :   };
     386          15 :   genesis->accounts[ vote_account_index ] = (fd_genesis_account_pair_t) {
     387          15 :     .key     = options->vote_pubkey,
     388          15 :     .account = (fd_genesis_account_t) {
     389          15 :       .lamports   = vote_min_bal,
     390          15 :       .data_len   = FD_VOTE_STATE_V3_SZ,
     391          15 :       .data       = vote_state_data,
     392          15 :       .owner      = fd_solana_vote_program_id
     393          15 :     }
     394          15 :   };
     395             : 
     396             :   /* Set up primordial accounts */
     397             : 
     398          15 :   ulong default_funded_balance = options->fund_initial_amount_lamports;
     399         159 :   for( ulong j=0UL; j<default_funded_cnt; j++ ) {
     400         144 :     fd_genesis_account_pair_t * pair = &genesis->accounts[ default_funded_idx+j ];
     401             : 
     402         144 :     uchar privkey[ 32 ] = {0};
     403         144 :     FD_STORE( ulong, privkey, j );
     404         144 :     fd_sha512_t sha[1];
     405         144 :     fd_ed25519_public_from_private( pair->key.key, privkey, sha );
     406             : 
     407         144 :     pair->account = (fd_genesis_account_t) {
     408         144 :       .lamports   = default_funded_balance,
     409         144 :       .data_len   = 0UL,
     410         144 :       .owner      = fd_solana_system_program_id
     411         144 :     };
     412         144 :   }
     413             : 
     414          15 : #define FEATURE_ENABLED_SZ 9UL
     415          15 :   static const uchar feature_enabled_data[ FEATURE_ENABLED_SZ ] = { 1, 0, 0, 0, 0, 0, 0, 0, 0 };
     416          15 :   ulong default_feature_enabled_balance = fd_rent_exempt_minimum_balance( &genesis->rent, FEATURE_ENABLED_SZ );
     417             : 
     418             :   /* Set up feature gate accounts */
     419          15 :   for( ulong j=0UL; j<feature_cnt; j++ ) {
     420           0 :     fd_genesis_account_pair_t * pair = &genesis->accounts[ feature_gate_idx+j ];
     421             : 
     422           0 :     pair->key     = features[ j ];
     423           0 :     pair->account = (fd_genesis_account_t) {
     424           0 :       .lamports   = default_feature_enabled_balance,
     425           0 :       .data_len   = FEATURE_ENABLED_SZ,
     426           0 :       .data       = (uchar *)feature_enabled_data,
     427           0 :       .owner      = fd_solana_feature_program_id
     428           0 :     };
     429           0 :   }
     430          15 : #undef FEATURE_ENABLED_SZ
     431             : 
     432             :   /* Sort and check for duplicates */
     433             : 
     434          15 :   sort_acct_inplace( genesis->accounts, genesis->accounts_len );
     435             : 
     436         204 :   for( ulong j=1UL; j < genesis->accounts_len; j++ ) {
     437         189 :     if( 0==memcmp( genesis->accounts[j-1].key.ul, genesis->accounts[j].key.ul, sizeof(fd_pubkey_t) ) ) {
     438           0 :       char dup_cstr[ FD_BASE58_ENCODED_32_SZ ];
     439           0 :       fd_base58_encode_32( genesis->accounts[j].key.uc, NULL, dup_cstr );
     440           0 :       FD_LOG_WARNING(( "Account %s is duplicate", dup_cstr ));
     441           0 :       return 0UL;
     442           0 :     }
     443         189 :   }
     444             : 
     445             :   /* Serialize bincode blob */
     446             : 
     447          15 :   ulong encoded_sz = genesis_encode( genesis, (uchar *)buf, bufsz );
     448          15 :   if( FD_UNLIKELY( !encoded_sz ) ) {
     449           3 :     FD_LOG_WARNING(( "Failed to encode genesis blob (bufsz=%lu)", bufsz ));
     450           3 :     return 0UL;
     451           3 :   }
     452          12 :   return encoded_sz;
     453             : 
     454          15 : # undef REQUIRE
     455          15 : }
     456             : 
     457             : ulong
     458             : fd_genesis_create( void *                       buf,
     459             :                    ulong                        bufsz,
     460          15 :                    fd_genesis_options_t const * options ) {
     461          15 :   fd_scratch_push();
     462          15 :   ulong ret = genesis_create( buf, bufsz, options );
     463          15 :   fd_scratch_pop();
     464          15 :   return ret;
     465          15 : }

Generated by: LCOV version 1.14