Line data Source code
1 : #define _GNU_SOURCE
2 : #define FD_SCRATCH_USE_HANDHOLDING 1
3 : #include "../../../shared/commands/configure/configure.h"
4 :
5 : #include "../../../platform/fd_file_util.h"
6 : #include "../../../../ballet/poh/fd_poh.h"
7 : #include "../../../../disco/keyguard/fd_keyload.h"
8 : #include "../../../../discof/genesis/genesis_hash.h"
9 : #include "../../../../flamenco/features/fd_features.h"
10 : #include "../../../../flamenco/genesis/fd_genesis_create.h"
11 : #include "../../../../flamenco/types/fd_types_custom.h"
12 : #include "../../../../flamenco/runtime/sysvar/fd_sysvar_clock.h"
13 :
14 : #include <stdio.h>
15 : #include <unistd.h>
16 : #include <dirent.h>
17 : #include <sys/stat.h>
18 : #include <sys/wait.h>
19 :
20 : #define NAME "genesis"
21 :
22 : /* default_enable_features is a table of features enabled by default */
23 :
24 : static void
25 0 : default_enable_features( fd_features_t * features ) {
26 0 : features->index_erasure_conflict_duplicate_proofs = 0UL;
27 0 : features->curve25519_restrict_msm_length = 0UL;
28 0 : features->commission_updates_only_allowed_in_first_half_of_epoch = 0UL;
29 0 : features->validate_fee_collector_account = 0UL;
30 0 : features->incremental_snapshot_only_incremental_hash_calculation = 0UL;
31 0 : features->timely_vote_credits = 0UL;
32 0 : features->apply_cost_tracker_during_replay = 0UL;
33 0 : features->reject_callx_r10 = 1UL;
34 0 : features->update_hashes_per_tick = 0UL;
35 0 : features->pico_inflation = 0UL;
36 0 : features->remaining_compute_units_syscall_enabled = 0UL;
37 0 : features->simplify_writable_program_account_check = 0UL;
38 0 : features->enable_bpf_loader_set_authority_checked_ix = 0UL;
39 0 : features->consume_blockstore_duplicate_proofs = 0UL;
40 0 : features->disable_deploy_of_alloc_free_syscall = 0UL;
41 0 : features->disable_bpf_loader_instructions = 0UL;
42 0 : features->full_inflation_enable = 0UL;
43 0 : features->vote_state_add_vote_latency = 0UL;
44 0 : features->curve25519_syscall_enabled = 0UL;
45 0 : features->error_on_syscall_bpf_function_hash_collisions = 0UL;
46 0 : features->update_hashes_per_tick3 = 0UL;
47 0 : features->update_hashes_per_tick4 = 0UL;
48 0 : features->enable_bpf_loader_extend_program_ix = 0UL;
49 0 : features->enable_loader_v4 = 0UL;
50 0 : features->increase_tx_account_lock_limit = 0UL;
51 0 : features->stake_raise_minimum_delegation_to_1_sol = 0UL;
52 0 : features->enable_alt_bn128_syscall = 0UL;
53 0 : features->revise_turbine_epoch_stakes = 0UL;
54 0 : features->clean_up_delegation_errors = 0UL;
55 0 : features->update_hashes_per_tick5 = 0UL;
56 0 : features->full_inflation_vote = 0UL;
57 0 : features->skip_rent_rewrites = 0UL;
58 0 : features->switch_to_new_elf_parser = 0UL;
59 0 : features->require_rent_exempt_split_destination = 0UL;
60 0 : features->enable_turbine_fanout_experiments = 0UL;
61 0 : features->devnet_and_testnet = 0UL;
62 0 : features->enable_big_mod_exp_syscall = 0UL;
63 0 : features->enable_alt_bn128_compression_syscall = 0UL;
64 0 : features->update_hashes_per_tick2 = 0UL;
65 0 : features->account_data_direct_mapping = 0UL;
66 0 : features->stricter_abi_and_runtime_constraints = 0UL;
67 0 : features->bpf_account_data_direct_mapping = 0UL;
68 0 : features->relax_authority_signer_check_for_lookup_table_creation = 0UL;
69 0 : features->update_hashes_per_tick6 = 0UL;
70 0 : features->enable_poseidon_syscall = 0UL;
71 0 : features->better_error_codes_for_tx_lamport_check = 0UL;
72 0 : features->stake_minimum_delegation_for_rewards = 0UL;
73 0 : features->loosen_cpi_size_restriction = 0UL;
74 0 : features->drop_legacy_shreds = 0UL;
75 0 : features->deprecate_rewards_sysvar = 0UL;
76 0 : features->warp_timestamp_again = 0UL;
77 0 : features->reduce_stake_warmup_cooldown = 0UL;
78 0 : features->disable_turbine_fanout_experiments = 0UL;
79 0 : features->blake3_syscall_enabled = 0UL;
80 0 : features->last_restart_slot_sysvar = 0UL;
81 0 : features->disable_fees_sysvar = 0UL;
82 0 : }
83 :
84 : /* estimate_hashes_per_tick approximates the PoH hashrate of the current
85 : tile. Spins PoH hashing for estimate_dur_ns nanoseconds. Returns
86 : the hashes per tick achieved, where tick_mhz is the target tick rate
87 : in ticks per microsecond (MHz). Assumes that the estimate duration
88 : is larger than the tick duration. */
89 :
90 : static ulong
91 : estimate_hashes_per_tick( ulong tick_mhz,
92 0 : ulong estimate_dur_ns ) {
93 0 : ulong const batch = 1UL<<20;
94 0 : long const deadline = fd_log_wallclock() + (long)estimate_dur_ns;
95 :
96 0 : uchar poh_hash[ 32 ] = {0};
97 0 : ulong hash_cnt = 0UL;
98 0 : do {
99 0 : fd_poh_append( poh_hash, batch );
100 0 : hash_cnt += batch;
101 0 : } while( fd_log_wallclock() < deadline );
102 :
103 0 : double hash_cnt_dbl = (double)hash_cnt;
104 0 : double tick_cnt_dbl = (double)estimate_dur_ns / ( (double)tick_mhz * 1000.0 );
105 0 : if( tick_cnt_dbl < 1.0 ) return 0UL;
106 :
107 : /* Apply 50% factor to the maximum machine hash rate. */
108 0 : double hashes_per_tick = hash_cnt_dbl / tick_cnt_dbl / 2.0;
109 0 : return (ulong)hashes_per_tick;
110 0 : }
111 :
112 :
113 : /* Create a new genesis.bin file contents into the provided blob buffer
114 : and return the size of the buffer. Will abort on error if the
115 : provided buffer is not large enough. */
116 :
117 : static ulong
118 : create_genesis( config_t const * config,
119 : uchar * blob,
120 0 : ulong blob_max ) {
121 :
122 0 : fd_genesis_options_t options[1];
123 :
124 : /* Read in keys */
125 :
126 0 : uchar const * identity_pubkey_ = fd_keyload_load( config->paths.identity_key, 1 );
127 0 : if( FD_UNLIKELY( !identity_pubkey_ ) ) FD_LOG_ERR(( "Failed to load identity key" ));
128 0 : memcpy( options->identity_pubkey.key, identity_pubkey_, 32 );
129 0 : fd_keyload_unload( identity_pubkey_, 1 );
130 :
131 0 : char file_path[ PATH_MAX ];
132 0 : FD_TEST( fd_cstr_printf_check( file_path, PATH_MAX, NULL, "%s/faucet.json", config->paths.base ) );
133 0 : uchar const * faucet_pubkey_ = fd_keyload_load( file_path, 1 );
134 0 : if( FD_UNLIKELY( !faucet_pubkey_ ) ) FD_LOG_ERR(( "Failed to load faucet key" ));
135 0 : memcpy( options->faucet_pubkey.key, faucet_pubkey_, 32 );
136 0 : fd_keyload_unload( faucet_pubkey_, 1 );
137 :
138 0 : FD_TEST( fd_cstr_printf_check( file_path, PATH_MAX, NULL, "%s/stake-account.json", config->paths.base ) );
139 0 : uchar const * stake_pubkey_ = fd_keyload_load( file_path, 1 );
140 0 : if( FD_UNLIKELY( !stake_pubkey_ ) ) FD_LOG_ERR(( "Failed to load stake account key" ));
141 0 : memcpy( options->stake_pubkey.key, stake_pubkey_, 32 );
142 0 : fd_keyload_unload( stake_pubkey_, 1 );
143 :
144 0 : if( !strcmp( config->paths.vote_account, "" ) ) {
145 0 : FD_TEST( fd_cstr_printf_check( file_path, PATH_MAX, NULL, "%s/vote-account.json", config->paths.base ) );
146 0 : } else {
147 0 : fd_cstr_fini( fd_cstr_append_cstr_safe( fd_cstr_init( file_path ), config->paths.vote_account, PATH_MAX-1UL ) );
148 0 : }
149 :
150 0 : uchar const * vote_pubkey_ = fd_keyload_load( file_path, 1 );
151 0 : if( FD_UNLIKELY( !vote_pubkey_ ) ) FD_LOG_ERR(( "Failed to load vote account key" ));
152 0 : memcpy( options->vote_pubkey.key, vote_pubkey_, 32 );
153 0 : fd_keyload_unload( vote_pubkey_, 1 );
154 :
155 0 : options->creation_time = (ulong)fd_log_wallclock() / (ulong)1e9;
156 0 : options->faucet_balance = 500000000000000000UL;
157 0 : options->vote_account_stake = config->development.genesis.vote_account_stake_lamports;
158 :
159 : /* Set up PoH config */
160 :
161 0 : if( 0UL==config->development.genesis.hashes_per_tick ) {
162 :
163 : /* set hashes_per_tick to whatever machine is capable of */
164 0 : ulong hashes_per_tick =
165 0 : estimate_hashes_per_tick( config->development.genesis.target_tick_duration_micros,
166 0 : (ulong)3e9 /* 3 seconds */ );
167 :
168 0 : if( hashes_per_tick == 0UL ) {
169 0 : FD_LOG_WARNING(( "PoH rate estimation failed. Defaulting to %lu",
170 0 : FD_SYSVAR_CLOCK_DEFAULT_HASHES_PER_TICK ));
171 0 : hashes_per_tick = FD_SYSVAR_CLOCK_DEFAULT_HASHES_PER_TICK;
172 0 : }
173 :
174 0 : options->hashes_per_tick = hashes_per_tick;
175 :
176 0 : } else if( 1UL==config->development.genesis.hashes_per_tick ) {
177 :
178 : /* set hashes_per_tick field to 0, which means sleep mode */
179 0 : options->hashes_per_tick = 0UL;
180 :
181 0 : } else {
182 :
183 : /* set hashes_per_tick to the specified value */
184 0 : options->hashes_per_tick = config->development.genesis.hashes_per_tick;
185 :
186 0 : }
187 :
188 0 : options->ticks_per_slot = config->development.genesis.ticks_per_slot;
189 0 : options->target_tick_duration_micros = config->development.genesis.target_tick_duration_micros;
190 :
191 0 : options->fund_initial_accounts = config->development.genesis.fund_initial_accounts;
192 0 : options->fund_initial_amount_lamports = config->development.genesis.fund_initial_amount_lamports;
193 :
194 0 : options->warmup_epochs = config->development.genesis.warmup_epochs;
195 :
196 0 : fd_features_t features[1];
197 0 : fd_features_disable_all( features );
198 0 : fd_cluster_version_t cluster_version = {
199 0 : .major = FD_DEFAULT_AGAVE_CLUSTER_VERSION_MAJOR,
200 0 : .minor = FD_DEFAULT_AGAVE_CLUSTER_VERSION_MINOR,
201 0 : .patch = FD_DEFAULT_AGAVE_CLUSTER_VERSION_PATCH
202 0 : };
203 0 : fd_features_enable_cleaned_up( features, &cluster_version );
204 0 : default_enable_features( features );
205 :
206 0 : options->features = features;
207 :
208 : /* Serialize blob */
209 :
210 0 : static uchar scratch_smem[ 1<<24UL ]; /* fits at least 32k accounts */
211 0 : ulong scratch_fmem[ 4 ];
212 0 : fd_scratch_attach( scratch_smem, scratch_fmem,
213 0 : sizeof(scratch_smem), sizeof(scratch_fmem)/sizeof(ulong) );
214 :
215 0 : ulong blob_sz = fd_genesis_create( blob, blob_max, options );
216 0 : if( FD_UNLIKELY( !blob_sz ) ) FD_LOG_ERR(( "Failed to create genesis blob" ));
217 :
218 0 : fd_scratch_detach( NULL );
219 :
220 0 : return blob_sz;
221 0 : }
222 :
223 : static void
224 0 : init( config_t const * config ) {
225 0 : int bootstrap = !config->gossip.entrypoints_cnt;
226 0 : if( FD_LIKELY( !bootstrap ) ) return;
227 :
228 0 : char _genesis_path[ PATH_MAX ];
229 0 : char const * genesis_path;
230 0 : if( FD_LIKELY( config->is_firedancer ) ) genesis_path = config->paths.genesis;
231 0 : else {
232 0 : genesis_path = _genesis_path;
233 0 : FD_TEST( fd_cstr_printf_check( _genesis_path, PATH_MAX, NULL, "%s/genesis.bin", config->frankendancer.paths.ledger ) );
234 0 : }
235 :
236 0 : if( FD_UNLIKELY( -1==fd_file_util_mkdir_all( genesis_path, config->uid, config->gid, 0 ) ) )
237 0 : FD_LOG_ERR(( "could not create ledger directory `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
238 :
239 0 : static uchar blob[ 1UL<<24UL ];
240 0 : ulong blob_sz = create_genesis( config, blob, sizeof(blob) );
241 :
242 : /* Switch to target user in the configuration when creating the
243 : genesis.bin file so it is permissioned correctly. */
244 :
245 0 : gid_t gid = getgid();
246 0 : uid_t uid = getuid();
247 0 : if( FD_LIKELY( gid == 0 && setegid( config->gid ) ) )
248 0 : FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
249 0 : if( FD_LIKELY( uid == 0 && seteuid( config->uid ) ) )
250 0 : FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
251 :
252 0 : mode_t previous = umask( S_IRWXO | S_IRWXG );
253 :
254 0 : do {
255 0 : FILE * genesis_file = fopen( genesis_path, "w" );
256 0 : FD_TEST( genesis_file );
257 0 : FD_TEST( 1L == fwrite( blob, blob_sz, 1L, genesis_file ) );
258 0 : FD_TEST( !fclose( genesis_file ) );
259 0 : } while(0);
260 :
261 0 : umask( previous );
262 :
263 0 : if( FD_UNLIKELY( seteuid( uid ) ) ) FD_LOG_ERR(( "seteuid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
264 0 : if( FD_UNLIKELY( setegid( gid ) ) ) FD_LOG_ERR(( "setegid() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
265 :
266 0 : uchar genesis_hash[ 32 ];
267 0 : char genesis_hash_cstr[ FD_BASE58_ENCODED_32_SZ ];
268 :
269 0 : ushort shred_version;
270 0 : int result = compute_shred_version( genesis_path, &shred_version, genesis_hash );
271 0 : if( FD_UNLIKELY( -1==result ) ) FD_LOG_ERR(( "could not compute shred version from genesis file `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
272 :
273 0 : FD_LOG_INFO(( "Created %s: genesis_hash=%s sz=%lu",
274 0 : genesis_path,
275 0 : fd_base58_encode_32( genesis_hash, NULL, genesis_hash_cstr ),
276 0 : blob_sz ));
277 0 : FD_LOG_INFO(( "Shred version: %hu", shred_version ));
278 0 : }
279 :
280 : static int
281 : fini( config_t const * config,
282 0 : int pre_init ) {
283 0 : (void)pre_init;
284 :
285 0 : char _genesis_path[ PATH_MAX ];
286 0 : char const * genesis_path;
287 0 : if( FD_LIKELY( config->is_firedancer ) ) genesis_path = config->paths.genesis;
288 0 : else {
289 0 : genesis_path = _genesis_path;
290 0 : FD_TEST( fd_cstr_printf_check( _genesis_path, PATH_MAX, NULL, "%s/genesis.bin", config->frankendancer.paths.ledger ) );
291 0 : }
292 :
293 0 : if( FD_UNLIKELY( -1==unlink( genesis_path ) && errno!=ENOENT ) )
294 0 : FD_LOG_ERR(( "could not remove genesis.bin file `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
295 0 : return 0;
296 0 : }
297 :
298 : static configure_result_t
299 : check( config_t const * config,
300 0 : int check_type FD_PARAM_UNUSED ) {
301 0 : if( FD_LIKELY( config->gossip.entrypoints_cnt ) ) CONFIGURE_OK();
302 :
303 0 : char _genesis_path[ PATH_MAX ];
304 0 : char const * genesis_path;
305 0 : if( FD_LIKELY( config->is_firedancer ) ) genesis_path = config->paths.genesis;
306 0 : else {
307 0 : genesis_path = _genesis_path;
308 0 : FD_TEST( fd_cstr_printf_check( _genesis_path, PATH_MAX, NULL, "%s/genesis.bin", config->frankendancer.paths.ledger ) );
309 0 : }
310 :
311 0 : struct stat st;
312 0 : int err = stat( genesis_path, &st );
313 0 : if( FD_UNLIKELY( -1==err && errno!=ENOENT ) ) FD_LOG_ERR(( "could not stat genesis.bin file at `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
314 0 : else if( FD_UNLIKELY( -1==err ) ) NOT_CONFIGURED( "`%s` does not exist", genesis_path );
315 :
316 0 : if( FD_UNLIKELY( !config->is_firedancer ) ) CHECK( check_dir( config->frankendancer.paths.ledger, config->uid, config->gid, S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR ) );
317 0 : CHECK( check_file( genesis_path, config->uid, config->gid, S_IFREG | S_IRUSR | S_IWUSR ) );
318 :
319 0 : static uchar buffer[ 1UL<<24UL ]; /* 16 MiB buffer should be enough for genesis */
320 0 : if( FD_UNLIKELY( (ulong)st.st_size>sizeof(buffer) ) ) FD_LOG_ERR(( "genesis file at `%s` too large (%lu bytes, max %lu)", genesis_path, (ulong)st.st_size, sizeof(buffer) ));
321 :
322 0 : ulong bytes_read = 0UL;
323 0 : int fd = open( genesis_path, O_RDONLY );
324 0 : if( FD_UNLIKELY( -1==fd ) ) FD_LOG_ERR(( "could not open genesis.bin file at `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
325 :
326 0 : while( bytes_read < (ulong)st.st_size ) {
327 0 : long result = read( fd, buffer + bytes_read, (ulong)st.st_size - bytes_read );
328 0 : if( FD_UNLIKELY( -1==result ) ) FD_LOG_ERR(( "could not read genesis.bin file at `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
329 0 : if( FD_UNLIKELY( !result ) ) FD_LOG_ERR(( "read() returned 0 before reading full genesis.bin file at `%s`", genesis_path ));
330 0 : bytes_read += (ulong)result;
331 0 : }
332 :
333 0 : fd_bincode_decode_ctx_t decode_ctx = {
334 0 : .data = buffer,
335 0 : .dataend = buffer+st.st_size,
336 0 : };
337 :
338 0 : if( FD_UNLIKELY( -1==close( fd ) ) ) FD_LOG_ERR(( "could not close genesis.bin file at `%s` (%i-%s)", genesis_path, errno, fd_io_strerror( errno ) ));
339 :
340 0 : ulong genesis_sz = 0UL;
341 0 : err = fd_genesis_solana_decode_footprint( &decode_ctx, &genesis_sz );
342 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) FD_LOG_ERR(( "malformed genesis file at `%s`", genesis_path ));
343 :
344 0 : static char _genesis[ 1UL<<24UL ] __attribute__((aligned(alignof(fd_genesis_solana_global_t)))); /* 16 MiB for decoded genesis */
345 0 : if( FD_UNLIKELY( genesis_sz>sizeof(_genesis) ) ) FD_LOG_ERR(( "genesis file at `%s` decode footprint too large (%lu bytes, max %lu)", genesis_path, genesis_sz, sizeof(_genesis) ));
346 :
347 0 : fd_genesis_solana_global_t * genesis = fd_genesis_solana_decode_global( _genesis, &decode_ctx );
348 :
349 0 : ulong tmp_genesis_sz = create_genesis( config, buffer, sizeof(buffer) );
350 :
351 0 : decode_ctx = (fd_bincode_decode_ctx_t){
352 0 : .data = buffer,
353 0 : .dataend = buffer+tmp_genesis_sz,
354 0 : };
355 :
356 0 : genesis_sz = 0UL;
357 0 : err = fd_genesis_solana_decode_footprint( &decode_ctx, &genesis_sz );
358 0 : if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) FD_LOG_ERR(( "malformed genesis file generated for comparison for `%s`", genesis_path ));
359 :
360 0 : static char _tmp_genesis[ 1UL<<24UL ] __attribute__((aligned(alignof(fd_genesis_solana_global_t)))); /* 16 MiB for decoded genesis */
361 0 : if( FD_UNLIKELY( genesis_sz>sizeof(_tmp_genesis) ) ) FD_LOG_ERR(( "genesis file generated for comparison for `%s` decode footprint too large (%lu bytes, max %lu)", genesis_path, genesis_sz, sizeof(_tmp_genesis) ));
362 :
363 0 : fd_genesis_solana_global_t * tmp_genesis = fd_genesis_solana_decode_global( _tmp_genesis, &decode_ctx );
364 :
365 : // ulong creation_time;
366 :
367 0 : if( FD_UNLIKELY( tmp_genesis->accounts_len!=genesis->accounts_len ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected accounts_len", genesis_path );
368 0 : fd_pubkey_account_pair_global_t * accounts = fd_genesis_solana_accounts_join( genesis );
369 0 : fd_pubkey_account_pair_global_t * tmp_accounts = fd_genesis_solana_accounts_join( tmp_genesis );
370 0 : for( ulong i=0UL; i<genesis->accounts_len; i++ ) {
371 0 : if( FD_UNLIKELY( memcmp( accounts[ i ].key.uc, tmp_accounts[ i ].key.uc, 32 ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account key at index %lu", genesis_path, i );
372 0 : if( FD_UNLIKELY( accounts[ i ].account.lamports!=tmp_accounts[ i ].account.lamports ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account lamports at index %lu", genesis_path, i );
373 0 : if( FD_UNLIKELY( accounts[ i ].account.data_len!=tmp_accounts[ i ].account.data_len ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account data_len at index %lu", genesis_path, i );
374 0 : if( FD_UNLIKELY( memcmp( accounts[ i ].account.owner.uc, tmp_accounts[ i ].account.owner.uc, 32 ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account owner at index %lu", genesis_path, i );
375 0 : if( FD_UNLIKELY( accounts[ i ].account.executable!=tmp_accounts[ i ].account.executable ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account executable flag at index %lu", genesis_path, i );
376 0 : if( FD_UNLIKELY( accounts[ i ].account.rent_epoch!=tmp_accounts[ i ].account.rent_epoch ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account rent_epoch at index %lu", genesis_path, i );
377 :
378 0 : uchar const * data = fd_solana_account_data_join( &accounts[ i ].account );
379 0 : uchar const * tmp_data = fd_solana_account_data_join( &tmp_accounts[ i ].account );
380 0 : if( FD_UNLIKELY( memcmp( data, tmp_data, accounts[ i ].account.data_len ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected account data at index %lu", genesis_path, i );
381 0 : }
382 :
383 0 : if( FD_UNLIKELY( tmp_genesis->native_instruction_processors_len!=genesis->native_instruction_processors_len ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected native_instruction_processors_len", genesis_path );
384 0 : fd_string_pubkey_pair_global_t * native_instruction_processors = fd_genesis_solana_native_instruction_processors_join( genesis );
385 0 : fd_string_pubkey_pair_global_t * tmp_native_instruction_processors = fd_genesis_solana_native_instruction_processors_join( tmp_genesis );
386 0 : for( ulong i=0UL; i<genesis->native_instruction_processors_len; i++ ) {
387 0 : if( FD_UNLIKELY( memcmp( native_instruction_processors[ i ].pubkey.uc, tmp_native_instruction_processors[ i ].pubkey.uc, 32 ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected native_instruction_processors pubkey at index %lu", genesis_path, i );
388 0 : if( FD_UNLIKELY( native_instruction_processors[ i ].string_len!=tmp_native_instruction_processors[ i ].string_len ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected native_instruction_processors string_len at index %lu", genesis_path, i );
389 0 : uchar const * str = fd_string_pubkey_pair_string_join( &native_instruction_processors[ i ] );
390 0 : uchar const * tmp_str = fd_string_pubkey_pair_string_join( &tmp_native_instruction_processors[ i ] );
391 0 : if( FD_UNLIKELY( memcmp( str, tmp_str, native_instruction_processors[ i ].string_len ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected native_instruction_processors string at index %lu", genesis_path, i );
392 0 : }
393 :
394 0 : if( FD_UNLIKELY( tmp_genesis->rewards_pools_len!=genesis->rewards_pools_len ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pools_len", genesis_path );
395 0 : fd_pubkey_account_pair_global_t * rewards_pool = fd_genesis_solana_rewards_pools_join( genesis );
396 0 : fd_pubkey_account_pair_global_t * tmp_rewards_pool = fd_genesis_solana_rewards_pools_join( tmp_genesis );
397 0 : for( ulong i=0UL; i<genesis->rewards_pools_len; i++ ) {
398 0 : if( FD_UNLIKELY( memcmp( rewards_pool[ i ].key.uc, tmp_rewards_pool[ i ].key.uc, 32 ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool key at index %lu", genesis_path, i );
399 0 : if( FD_UNLIKELY( rewards_pool[ i ].account.lamports!=tmp_rewards_pool[ i ].account.lamports ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool account lamports at index %lu", genesis_path, i );
400 0 : if( FD_UNLIKELY( rewards_pool[ i ].account.data_len!=tmp_rewards_pool[ i ].account.data_len ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool account data_len at index %lu", genesis_path, i );
401 0 : if( FD_UNLIKELY( memcmp( rewards_pool[ i ].account.owner.uc, tmp_rewards_pool[ i ].account.owner.uc, 32 ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool account owner at index %lu", genesis_path, i );
402 0 : if( FD_UNLIKELY( rewards_pool[ i ].account.executable!=tmp_rewards_pool[ i ].account.executable ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool account executable flag at index %lu", genesis_path, i );
403 0 : if( FD_UNLIKELY( rewards_pool[ i ].account.rent_epoch!=tmp_rewards_pool[ i ].account.rent_epoch ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool account rent_epoch at index %lu", genesis_path, i );
404 :
405 0 : uchar const * data = fd_solana_account_data_join( &rewards_pool[ i ].account );
406 0 : uchar const * tmp_data = fd_solana_account_data_join( &tmp_rewards_pool[ i ].account );
407 0 : if( FD_UNLIKELY( memcmp( data, tmp_data, rewards_pool[ i ].account.data_len ) ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rewards_pool account data at index %lu", genesis_path, i );
408 0 : }
409 :
410 0 : if( FD_UNLIKELY( tmp_genesis->ticks_per_slot!=config->development.genesis.ticks_per_slot ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected ticks_per_slot", genesis_path );
411 :
412 : // ulong unused;
413 :
414 0 : if( FD_UNLIKELY( tmp_genesis->poh_config.target_tick_duration.seconds!=genesis->poh_config.target_tick_duration.seconds ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected poh_config.target_tick_duration.seconds", genesis_path );
415 0 : if( FD_UNLIKELY( tmp_genesis->poh_config.target_tick_duration.nanoseconds!=genesis->poh_config.target_tick_duration.nanoseconds ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected poh_config.target_tick_duration.nanoseconds", genesis_path );
416 0 : if( FD_UNLIKELY( tmp_genesis->poh_config.target_tick_count!=genesis->poh_config.target_tick_count ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected poh_config.target_tick_count", genesis_path );
417 0 : if( FD_UNLIKELY( tmp_genesis->poh_config.has_target_tick_count!=genesis->poh_config.has_target_tick_count ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected poh_config.has_target_tick_count", genesis_path );
418 0 : if( FD_UNLIKELY( tmp_genesis->poh_config.hashes_per_tick!=genesis->poh_config.hashes_per_tick ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected poh_config.hashes_per_tick", genesis_path );
419 0 : if( FD_UNLIKELY( tmp_genesis->poh_config.has_hashes_per_tick!=genesis->poh_config.has_hashes_per_tick ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected poh_config.has_hashes_per_tick", genesis_path );
420 :
421 : // ulong __backwards_compat_with_v0_23;
422 :
423 0 : if( FD_UNLIKELY( tmp_genesis->fee_rate_governor.target_lamports_per_signature!=genesis->fee_rate_governor.target_lamports_per_signature ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected fee_rate_governor.target_lamports_per_signature", genesis_path );
424 0 : if( FD_UNLIKELY( tmp_genesis->fee_rate_governor.target_signatures_per_slot!=genesis->fee_rate_governor.target_signatures_per_slot ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected fee_rate_governor.target_signatures_per_slot", genesis_path );
425 0 : if( FD_UNLIKELY( tmp_genesis->fee_rate_governor.min_lamports_per_signature!=genesis->fee_rate_governor.min_lamports_per_signature ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected fee_rate_governor.min_lamports_per_signature", genesis_path );
426 0 : if( FD_UNLIKELY( tmp_genesis->fee_rate_governor.max_lamports_per_signature!=genesis->fee_rate_governor.max_lamports_per_signature ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected fee_rate_governor.max_lamports_per_signature", genesis_path );
427 0 : if( FD_UNLIKELY( tmp_genesis->fee_rate_governor.burn_percent!=genesis->fee_rate_governor.burn_percent ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected fee_rate_governor.burn_percent", genesis_path );
428 :
429 0 : if( FD_UNLIKELY( tmp_genesis->rent.lamports_per_uint8_year!=genesis->rent.lamports_per_uint8_year ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rent.lamports_per_uint8_year", genesis_path );
430 0 : if( FD_UNLIKELY( tmp_genesis->rent.exemption_threshold!=genesis->rent.exemption_threshold ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rent.exemption_threshold", genesis_path );
431 0 : if( FD_UNLIKELY( tmp_genesis->rent.burn_percent!=genesis->rent.burn_percent ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected rent.burn_percent", genesis_path );
432 :
433 0 : if( FD_UNLIKELY( tmp_genesis->inflation.initial!=genesis->inflation.initial ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected inflation.initial", genesis_path );
434 0 : if( FD_UNLIKELY( tmp_genesis->inflation.terminal!=genesis->inflation.terminal ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected inflation.terminal", genesis_path );
435 0 : if( FD_UNLIKELY( tmp_genesis->inflation.taper!=genesis->inflation.taper ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected inflation.taper", genesis_path );
436 0 : if( FD_UNLIKELY( tmp_genesis->inflation.foundation!=genesis->inflation.foundation ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected inflation.foundation", genesis_path );
437 0 : if( FD_UNLIKELY( tmp_genesis->inflation.foundation_term!=genesis->inflation.foundation_term ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected inflation.foundation_term", genesis_path );
438 : // double inflation.unused
439 :
440 0 : if( FD_UNLIKELY( tmp_genesis->epoch_schedule.slots_per_epoch!=genesis->epoch_schedule.slots_per_epoch ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected epoch_schedule.slots_per_epoch", genesis_path );
441 0 : if( FD_UNLIKELY( tmp_genesis->epoch_schedule.leader_schedule_slot_offset!=genesis->epoch_schedule.leader_schedule_slot_offset ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected epoch_schedule.leader_schedule_slot_offset", genesis_path );
442 0 : if( FD_UNLIKELY( tmp_genesis->epoch_schedule.warmup!=genesis->epoch_schedule.warmup ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected epoch_schedule.warmup", genesis_path );
443 0 : if( FD_UNLIKELY( tmp_genesis->epoch_schedule.first_normal_epoch!=genesis->epoch_schedule.first_normal_epoch ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected epoch_schedule.first_normal_epoch", genesis_path );
444 0 : if( FD_UNLIKELY( tmp_genesis->epoch_schedule.first_normal_slot!=genesis->epoch_schedule.first_normal_slot ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected epoch_schedule.first_normal_slot", genesis_path );
445 :
446 0 : if( FD_UNLIKELY( tmp_genesis->cluster_type!=genesis->cluster_type ) ) PARTIALLY_CONFIGURED( "`%s` has unexpected cluster_type", genesis_path );
447 :
448 0 : CONFIGURE_OK();
449 0 : }
450 :
451 : configure_stage_t fd_cfg_stage_genesis = {
452 : .name = NAME,
453 : .init = init,
454 : .fini = fini,
455 : .check = check,
456 : };
457 :
458 : #undef NAME
|