diff --git a/src/app/fdctl/topology.c b/src/app/fdctl/topology.c index 87eb764091..b812e3e24c 100644 --- a/src/app/fdctl/topology.c +++ b/src/app/fdctl/topology.c @@ -3,6 +3,7 @@ #include "../../disco/net/fd_net_tile.h" #include "../../disco/quic/fd_tpu.h" #include "../../disco/tiles.h" +#include "../../disco/fd_txn_m_t.h" #include "../../disco/topo/fd_topob.h" #include "../../disco/topo/fd_cpu_topo.h" #include "../../disco/plugin/fd_plugin.h" diff --git a/src/app/firedancer/topology.c b/src/app/firedancer/topology.c index 3fd8f0af56..79acc8b34b 100644 --- a/src/app/firedancer/topology.c +++ b/src/app/firedancer/topology.c @@ -4,11 +4,13 @@ #include "../../disco/net/fd_net_tile.h" #include "../../disco/quic/fd_tpu.h" #include "../../disco/tiles.h" +#include "../../disco/fd_txn_m_t.h" #include "../../disco/topo/fd_topob.h" #include "../../disco/topo/fd_cpu_topo.h" +#include "../../disco/pack/fd_microblock.h" #include "../../util/pod/fd_pod_format.h" +#include "../../ballet/reedsol/fd_reedsol.h" #include "../../flamenco/runtime/fd_blockstore.h" -#include "../../flamenco/runtime/fd_txncache.h" #include "../../flamenco/snapshot/fd_snapshot_base.h" #include "../../util/tile/fd_tile_private.h" #include "../../discof/restore/utils/fd_snapshot_messages.h" diff --git a/src/app/ledger/main.c b/src/app/ledger/main.c index 107b24f71d..ecb7cf6f81 100644 --- a/src/app/ledger/main.c +++ b/src/app/ledger/main.c @@ -2,18 +2,21 @@ #include "../../flamenco/fd_flamenco.h" #include "../../flamenco/runtime/fd_hashes.h" #include "../../flamenco/types/fd_types.h" +#include "../../flamenco/features/fd_features.h" #include "../../flamenco/runtime/fd_runtime.h" +#include "../../flamenco/runtime/fd_runtime_init.h" +#include "../../flamenco/runtime/fd_runtime_err.h" #include "../../flamenco/runtime/fd_runtime_public.h" #include "../../flamenco/runtime/fd_rocksdb.h" -#include "../../flamenco/runtime/fd_txncache.h" #include "../../flamenco/rewards/fd_rewards.h" #include "../../ballet/base58/fd_base58.h" #include "../../flamenco/runtime/context/fd_capture_ctx.h" #include "../../flamenco/runtime/fd_blockstore.h" #include "../../flamenco/shredcap/fd_shredcap.h" -#include "../../flamenco/runtime/program/fd_bpf_program_util.h" #include "../../flamenco/snapshot/fd_snapshot.h" +#include + struct fd_ledger_args { fd_wksp_t * wksp; /* wksp for blockstore */ fd_wksp_t * funk_wksp; /* wksp for funk */ @@ -164,9 +167,12 @@ runtime_replay( fd_ledger_args_t * ledger_args ) { fd_features_restore( ledger_args->slot_ctx, ledger_args->runtime_spad ); - fd_runtime_update_leaders( ledger_args->slot_ctx->bank, fd_bank_slot_get( ledger_args->slot_ctx->bank ), ledger_args->runtime_spad ); + fd_runtime_update_leaders( + ledger_args->slot_ctx, + fd_bank_slot_get( ledger_args->slot_ctx->bank ), + ledger_args->runtime_spad ); - fd_calculate_epoch_accounts_hash_values( ledger_args->slot_ctx ); + fd_calculate_epoch_accounts_hash_values( ledger_args->slot_ctx->bank ); long replay_time = -fd_log_wallclock(); ulong txn_cnt = 0; @@ -519,8 +525,8 @@ fd_ledger_main_setup( fd_ledger_args_t * args ) { /* Finish other runtime setup steps */ fd_features_restore( args->slot_ctx, args->runtime_spad ); - fd_runtime_update_leaders( args->slot_ctx->bank, fd_bank_slot_get( args->slot_ctx->bank ), args->runtime_spad ); - fd_calculate_epoch_accounts_hash_values( args->slot_ctx ); + fd_runtime_update_leaders( args->slot_ctx, fd_bank_slot_get( args->slot_ctx->bank ), args->runtime_spad ); + fd_calculate_epoch_accounts_hash_values( args->slot_ctx->bank ); /* After both snapshots have been loaded in, we can determine if we should start distributing rewards. */ diff --git a/src/app/shared_dev/commands/bundle_client.c b/src/app/shared_dev/commands/bundle_client.c index a794621096..5c80f91c0d 100644 --- a/src/app/shared_dev/commands/bundle_client.c +++ b/src/app/shared_dev/commands/bundle_client.c @@ -1,6 +1,6 @@ #include "../../shared/fd_config.h" #include "../../shared/commands/run/run.h" -#include "../../../disco/tiles.h" +#include "../../../disco/fd_txn_m_t.h" #include "../../../disco/topo/fd_topob.h" #include /* pause */ diff --git a/src/disco/archiver/fd_archiver_feeder.c b/src/disco/archiver/fd_archiver_feeder.c index 195d5f7164..cf2773be3e 100644 --- a/src/disco/archiver/fd_archiver_feeder.c +++ b/src/disco/archiver/fd_archiver_feeder.c @@ -1,4 +1,4 @@ -#include "../tiles.h" +#include "../topo/fd_topo.h" #include "fd_archiver.h" #include diff --git a/src/disco/archiver/fd_archiver_playback.c b/src/disco/archiver/fd_archiver_playback.c index c6ebefcc94..bc28c850ba 100644 --- a/src/disco/archiver/fd_archiver_playback.c +++ b/src/disco/archiver/fd_archiver_playback.c @@ -1,6 +1,6 @@ #define _GNU_SOURCE /* Enable GNU and POSIX extensions */ -#include "../tiles.h" +#include "../topo/fd_topo.h" #include "fd_archiver.h" #include diff --git a/src/disco/archiver/fd_archiver_writer.c b/src/disco/archiver/fd_archiver_writer.c index 0e968b9ca6..a981fb26c0 100644 --- a/src/disco/archiver/fd_archiver_writer.c +++ b/src/disco/archiver/fd_archiver_writer.c @@ -1,6 +1,6 @@ #define _GNU_SOURCE /* Enable GNU and POSIX extensions */ -#include "../tiles.h" +#include "../topo/fd_topo.h" #include "fd_archiver.h" #include diff --git a/src/disco/bundle/fd_bundle_crank.c b/src/disco/bundle/fd_bundle_crank.c index 50d3ff8363..58b5608d94 100644 --- a/src/disco/bundle/fd_bundle_crank.c +++ b/src/disco/bundle/fd_bundle_crank.c @@ -1,5 +1,8 @@ #include "fd_bundle_crank.h" #include "../../flamenco/runtime/fd_pubkey_utils.h" +#if FD_HAS_AVX +#include "../../util/simd/fd_avx.h" +#endif #if FD_HAS_AVX #include "../../util/simd/fd_avx.h" diff --git a/src/disco/dedup/fd_dedup_tile.c b/src/disco/dedup/fd_dedup_tile.c index 9b5c7aa5a3..f6c59f3f65 100644 --- a/src/disco/dedup/fd_dedup_tile.c +++ b/src/disco/dedup/fd_dedup_tile.c @@ -1,8 +1,6 @@ -#include "../tiles.h" - +#include "../topo/fd_topo.h" +#include "../fd_txn_m_t.h" #include "generated/fd_dedup_tile_seccomp.h" - -#include "../verify/fd_verify_tile.h" #include "../metrics/fd_metrics.h" #include diff --git a/src/disco/pack/fd_pack_tile.c b/src/disco/pack/fd_pack_tile.c index 9bad1f1a2d..badd108d2a 100644 --- a/src/disco/pack/fd_pack_tile.c +++ b/src/disco/pack/fd_pack_tile.c @@ -1,4 +1,6 @@ #include "../tiles.h" +#include "../fd_txn_m_t.h" +#include "../topo/fd_topo.h" #include "generated/fd_pack_tile_seccomp.h" diff --git a/src/disco/plugin/fd_plugin_tile.c b/src/disco/plugin/fd_plugin_tile.c index 59284da604..244d1807fb 100644 --- a/src/disco/plugin/fd_plugin_tile.c +++ b/src/disco/plugin/fd_plugin_tile.c @@ -1,4 +1,4 @@ -#include "../tiles.h" +#include "../topo/fd_topo.h" #include "generated/fd_plugin_tile_seccomp.h" diff --git a/src/disco/shred/fd_shred_tile.c b/src/disco/shred/fd_shred_tile.c index 6517e926db..ba38f526c7 100644 --- a/src/disco/shred/fd_shred_tile.c +++ b/src/disco/shred/fd_shred_tile.c @@ -1,4 +1,5 @@ #include "../tiles.h" +#include "../topo/fd_topo.h" #include "generated/fd_shred_tile_seccomp.h" #include "../../util/pod/fd_pod_format.h" diff --git a/src/disco/sign/fd_sign_tile.c b/src/disco/sign/fd_sign_tile.c index 8ca0289e89..daf048f1f4 100644 --- a/src/disco/sign/fd_sign_tile.c +++ b/src/disco/sign/fd_sign_tile.c @@ -1,5 +1,5 @@ #define _GNU_SOURCE -#include "../tiles.h" +#include "../topo/fd_topo.h" #include "generated/fd_sign_tile_seccomp.h" diff --git a/src/disco/tiles.h b/src/disco/tiles.h index 1f329e9d1f..b3f1303d7b 100644 --- a/src/disco/tiles.h +++ b/src/disco/tiles.h @@ -1,13 +1,8 @@ #ifndef HEADER_fd_src_app_fdctl_run_tiles_h #define HEADER_fd_src_app_fdctl_run_tiles_h -#include "stem/fd_stem.h" -#include "shred/fd_shredder.h" #include "../ballet/shred/fd_shred.h" -#include "pack/fd_pack.h" -#include "topo/fd_topo.h" #include "bundle/fd_bundle_crank.h" -#include "fd_txn_m_t.h" #include diff --git a/src/discof/exec/fd_exec_tile.c b/src/discof/exec/fd_exec_tile.c index af93e86e2d..2c6b4cfe61 100644 --- a/src/discof/exec/fd_exec_tile.c +++ b/src/discof/exec/fd_exec_tile.c @@ -1,9 +1,11 @@ -#include "../../disco/tiles.h" +#include "../../disco/topo/fd_topo.h" #include "generated/fd_exec_tile_seccomp.h" #include "../../util/pod/fd_pod_format.h" +#include "../../disco/pack/fd_pack.h" #include "../../flamenco/runtime/context/fd_capture_ctx.h" #include "../../flamenco/runtime/fd_runtime.h" +#include "../../flamenco/runtime/fd_runtime_err.h" #include "../../flamenco/runtime/fd_runtime_public.h" #include "../../flamenco/runtime/fd_executor.h" #include "../../flamenco/runtime/fd_hashes.h" @@ -36,7 +38,6 @@ struct fd_exec_tile_ctx { /* Runtime public and local joins of its members. */ fd_wksp_t * runtime_public_wksp; fd_runtime_public_t * runtime_public; - fd_spad_t const * runtime_spad; /* Shared bank hash cmp object. */ fd_bank_hash_cmp_t * bank_hash_cmp; @@ -432,11 +433,6 @@ unprivileged_init( fd_topo_t * topo, FD_LOG_ERR(( "Failed to join runtime public" )); } - ctx->runtime_spad = fd_runtime_public_spad( ctx->runtime_public ); - if( FD_UNLIKELY( !ctx->runtime_spad ) ) { - FD_LOG_ERR(( "Failed to get and join runtime spad" )); - } - /********************************************************************/ /* banks */ /********************************************************************/ diff --git a/src/discof/poh/fd_poh_tile.c b/src/discof/poh/fd_poh_tile.c index 9b5436a621..5eb7e56109 100644 --- a/src/discof/poh/fd_poh_tile.c +++ b/src/discof/poh/fd_poh_tile.c @@ -311,15 +311,16 @@ #include "../../disco/tiles.h" #include "../../disco/bundle/fd_bundle_crank.h" #include "../../disco/pack/fd_pack.h" +#include "../../disco/topo/fd_topo.h" #include "../../ballet/sha256/fd_sha256.h" #include "../../disco/metrics/fd_metrics.h" -#include "../../util/pod/fd_pod.h" #include "../../disco/shred/fd_shredder.h" #include "../../disco/keyguard/fd_keyload.h" #include "../../disco/keyguard/fd_keyswitch.h" #include "../../disco/metrics/generated/fd_metrics_poh.h" #include "../../disco/plugin/fd_plugin.h" #include "../../flamenco/leaders/fd_multi_epoch_leaders.h" +#include "../../util/pod/fd_pod.h" #include diff --git a/src/discof/replay/fd_exec.c b/src/discof/replay/fd_exec.c index ab1fca0944..64e4297682 100644 --- a/src/discof/replay/fd_exec.c +++ b/src/discof/replay/fd_exec.c @@ -1,4 +1,5 @@ #include "fd_exec.h" +#include "../../ballet/block/fd_microblock.h" fd_slice_exec_t * fd_slice_exec_join( void * slmem ) { diff --git a/src/discof/replay/fd_exec.h b/src/discof/replay/fd_exec.h index 8d4dd7ddc7..eeb097ddf0 100644 --- a/src/discof/replay/fd_exec.h +++ b/src/discof/replay/fd_exec.h @@ -24,13 +24,14 @@ generate_stake_weight_msg( fd_exec_slot_ctx_t * slot_ctx, runtime_spad ); fd_bank_epoch_stakes_end_locking_query( slot_ctx->bank ); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); + fd_epoch_schedule_t epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); stake_weight_msg->epoch = epoch; - stake_weight_msg->staked_cnt = stake_weight_idx; /* staked_cnt */ - stake_weight_msg->start_slot = fd_epoch_slot0( epoch_schedule, stake_weight_msg_out[0] ); /* start_slot */ - stake_weight_msg->slot_cnt = epoch_schedule->slots_per_epoch; /* slot_cnt */ - stake_weight_msg->excluded_stake = 0UL; /* excluded stake */ + stake_weight_msg->staked_cnt = stake_weight_idx; /* staked_cnt */ + stake_weight_msg->start_slot = fd_epoch_slot0( &epoch_schedule, stake_weight_msg_out[0] ); /* start_slot */ + stake_weight_msg->slot_cnt = epoch_schedule.slots_per_epoch; /* slot_cnt */ + stake_weight_msg->excluded_stake = 0UL; /* excluded stake */ return 5*sizeof(ulong) + (stake_weight_idx * sizeof(fd_stake_weight_t)); } diff --git a/src/discof/replay/fd_replay_tile.c b/src/discof/replay/fd_replay_tile.c index 541d31dff3..5e04e14650 100644 --- a/src/discof/replay/fd_replay_tile.c +++ b/src/discof/replay/fd_replay_tile.c @@ -1,5 +1,7 @@ #define _GNU_SOURCE #include "../../disco/tiles.h" +#include "../../disco/topo/fd_topo.h" +#include "../../disco/pack/fd_pack.h" #include "generated/fd_replay_tile_seccomp.h" #include "fd_replay_notif.h" @@ -9,18 +11,16 @@ #include "../../flamenco/runtime/fd_txncache.h" #include "../../flamenco/runtime/context/fd_capture_ctx.h" #include "../../flamenco/runtime/context/fd_exec_slot_ctx.h" -#include "../../flamenco/runtime/program/fd_bpf_program_util.h" -#include "../../flamenco/runtime/sysvar/fd_sysvar_slot_history.h" -#include "../../flamenco/runtime/fd_hashes.h" #include "../../flamenco/runtime/fd_runtime_init.h" +#include "../../flamenco/runtime/fd_hashes.h" #include "../../flamenco/snapshot/fd_snapshot.h" -#include "../../flamenco/stakes/fd_stakes.h" #include "../../flamenco/runtime/fd_runtime.h" +#include "../../flamenco/runtime/fd_runtime_err.h" #include "../../flamenco/runtime/fd_runtime_public.h" #include "../../flamenco/rewards/fd_rewards.h" #include "../../disco/metrics/fd_metrics.h" -#include "../../choreo/fd_choreo.h" #include "../../disco/plugin/fd_plugin.h" +#include "../../choreo/forks/fd_forks.h" #include "fd_exec.h" #include "../../discof/restore/utils/fd_snapshot_messages.h" @@ -307,14 +307,15 @@ static void publish_stake_weights( fd_replay_tile_ctx_t * ctx, fd_stem_context_t * stem, fd_exec_slot_ctx_t * slot_ctx ) { - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); + fd_epoch_schedule_t epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); fd_vote_accounts_global_t const * epoch_stakes = fd_bank_epoch_stakes_locking_query( slot_ctx->bank ); fd_vote_accounts_pair_global_t_mapnode_t * epoch_stakes_root = fd_vote_accounts_vote_accounts_root_join( epoch_stakes ); if( epoch_stakes_root!=NULL ) { ulong * stake_weights_msg = fd_chunk_to_laddr( ctx->stake_out->mem, ctx->stake_out->chunk ); - ulong epoch = fd_slot_to_leader_schedule_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ) ); + ulong epoch = fd_slot_to_leader_schedule_epoch( &epoch_schedule, fd_bank_slot_get( slot_ctx->bank ) ); ulong stake_weights_sz = generate_stake_weight_msg( slot_ctx, ctx->runtime_spad, epoch - 1, stake_weights_msg ); ulong stake_weights_sig = 4UL; fd_stem_publish( stem, 0UL, stake_weights_sig, ctx->stake_out->chunk, stake_weights_sz, 0UL, 0UL, fd_frag_meta_ts_comp( fd_tickcount() ) ); @@ -329,7 +330,7 @@ publish_stake_weights( fd_replay_tile_ctx_t * ctx, if( next_epoch_stakes_root!=NULL ) { ulong * stake_weights_msg = fd_chunk_to_laddr( ctx->stake_out->mem, ctx->stake_out->chunk ); - ulong epoch = fd_slot_to_leader_schedule_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ) ); /* epoch */ + ulong epoch = fd_slot_to_leader_schedule_epoch( &epoch_schedule, fd_bank_slot_get( slot_ctx->bank ) ); /* epoch */ ulong stake_weights_sz = generate_stake_weight_msg( slot_ctx, ctx->runtime_spad, epoch, stake_weights_msg ); ulong stake_weights_sig = 4UL; fd_stem_publish( stem, 0UL, stake_weights_sig, ctx->stake_out->chunk, stake_weights_sz, 0UL, 0UL, fd_frag_meta_ts_comp( fd_tickcount() ) ); @@ -721,8 +722,9 @@ publish_slot_notifications( fd_replay_tile_ctx_t * ctx, msg->slot_exec.bank_hash = fd_bank_bank_hash_get( ctx->slot_ctx->bank ); - fd_block_hash_queue_global_t const * block_hash_queue = fd_bank_block_hash_queue_query( ctx->slot_ctx->bank ); - fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( block_hash_queue ); + fd_blockhashes_t const * block_hash_queue = fd_bank_block_hash_queue_query( ctx->slot_ctx->bank ); + fd_hash_t const * last_hash = fd_blockhashes_peek_last( block_hash_queue ); + FD_TEST( last_hash ); msg->slot_exec.block_hash = *last_hash; memcpy( &msg->slot_exec.identity, ctx->validator_identity_pubkey, sizeof( fd_pubkey_t ) ); @@ -789,7 +791,7 @@ init_after_snapshot( fd_replay_tile_ctx_t * ctx, /* FIXME: This branch does not set up a new block exec ctx properly. Needs to do whatever prepare_new_block_execution does, but just hacking that in breaks stuff. */ - fd_runtime_update_leaders( ctx->slot_ctx->bank, + fd_runtime_update_leaders( ctx->slot_ctx, fd_bank_slot_get( ctx->slot_ctx->bank ), ctx->runtime_spad ); @@ -897,7 +899,7 @@ static void init_from_snapshot( fd_replay_tile_ctx_t * ctx, fd_stem_context_t * stem ) { fd_features_restore( ctx->slot_ctx, ctx->runtime_spad ); - fd_calculate_epoch_accounts_hash_values( ctx->slot_ctx ); + fd_calculate_epoch_accounts_hash_values( ctx->slot_ctx->bank ); fd_slot_lthash_t const * lthash = fd_bank_lthash_query( ctx->slot_ctx->bank ); if( fd_lthash_is_zero( (fd_lthash_value_t * )lthash ) ) { @@ -921,9 +923,10 @@ init_from_snapshot( fd_replay_tile_ctx_t * ctx, fd_memcpy( (fd_lthash_value_t *)fd_type_pun(lthash_val->lthash), <hash_buf, sizeof(lthash_buf) ); } - fd_runtime_update_leaders( ctx->slot_ctx->bank, - fd_bank_slot_get( ctx->slot_ctx->bank ), - ctx->runtime_spad ); + fd_runtime_update_leaders( + ctx->slot_ctx, + fd_bank_slot_get( ctx->slot_ctx->bank ), + ctx->runtime_spad ); fd_runtime_read_genesis( ctx->slot_ctx, ctx->genesis, @@ -1271,12 +1274,12 @@ init_poh( fd_replay_tile_ctx_t * ctx ) { msg->ticks_per_slot = fd_bank_ticks_per_slot_get( ctx->slot_ctx->bank ); msg->tick_duration_ns = (ulong)(fd_bank_ns_per_slot_get( ctx->slot_ctx->bank )) / fd_bank_ticks_per_slot_get( ctx->slot_ctx->bank ); - fd_block_hash_queue_global_t * bhq = (fd_block_hash_queue_global_t *)&ctx->slot_ctx->bank->block_hash_queue[0]; - fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( bhq ); + fd_blockhashes_t const * bhq = fd_bank_block_hash_queue_query( ctx->slot_ctx->bank ); + fd_hash_t const * last_hash = fd_blockhashes_peek_last( bhq ); if( last_hash ) { - memcpy(msg->last_entry_hash, last_hash, sizeof(fd_hash_t)); + memcpy( msg->last_entry_hash, last_hash, sizeof(fd_hash_t) ); } else { - memset(msg->last_entry_hash, 0UL, sizeof(fd_hash_t)); + memset( msg->last_entry_hash, 0UL, sizeof(fd_hash_t) ); } msg->tick_height = fd_bank_slot_get( ctx->slot_ctx->bank ) * msg->ticks_per_slot; @@ -1842,8 +1845,9 @@ after_credit( fd_replay_tile_ctx_t * ctx, if( FD_LIKELY( ctx->tower_out_idx!=ULONG_MAX && !ctx->read_only ) ) { uchar * chunk_laddr = fd_chunk_to_laddr( ctx->tower_out_mem, ctx->tower_out_chunk ); fd_hash_t const * bank_hash = fd_bank_bank_hash_query( ctx->slot_ctx->bank ); - fd_block_hash_queue_global_t * block_hash_queue = (fd_block_hash_queue_global_t *)&ctx->slot_ctx->bank->block_hash_queue[0]; - fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( block_hash_queue ); + fd_blockhashes_t const * block_hash_queue = fd_bank_block_hash_queue_query( ctx->slot_ctx->bank ); + fd_hash_t const * last_hash = fd_blockhashes_peek_last( block_hash_queue ); + FD_TEST( last_hash ); memcpy( chunk_laddr, bank_hash, sizeof(fd_hash_t) ); memcpy( chunk_laddr+sizeof(fd_hash_t), last_hash, sizeof(fd_hash_t) ); diff --git a/src/discof/writer/fd_writer_tile.c b/src/discof/writer/fd_writer_tile.c index 56725c8dd0..d77e0a07e3 100644 --- a/src/discof/writer/fd_writer_tile.c +++ b/src/discof/writer/fd_writer_tile.c @@ -1,12 +1,12 @@ #define _GNU_SOURCE -#include "../../disco/tiles.h" +#include "../../disco/pack/fd_pack.h" +#include "../../disco/topo/fd_topo.h" #include "generated/fd_writer_tile_seccomp.h" #include "../../util/pod/fd_pod_format.h" #include "../../flamenco/runtime/fd_runtime.h" #include "../../flamenco/runtime/fd_runtime_public.h" -#include "../../flamenco/runtime/fd_executor.h" #include "../../funk/fd_funk.h" @@ -37,7 +37,6 @@ struct fd_writer_tile_ctx { /* Runtime public and local joins of its members. */ fd_wksp_t const * runtime_public_wksp; fd_runtime_public_t const * runtime_public; - fd_spad_t const * runtime_spad; /* Local joins of exec spads. Read-only. */ fd_spad_t * exec_spad[ FD_PACK_MAX_BANK_TILES ]; @@ -287,11 +286,6 @@ unprivileged_init( fd_topo_t * topo, FD_LOG_ERR(( "Failed to join runtime public" )); } - ctx->runtime_spad = fd_runtime_public_spad( ctx->runtime_public ); - if( FD_UNLIKELY( !ctx->runtime_spad ) ) { - FD_LOG_ERR(( "Failed to get and join runtime spad" )); - } - /********************************************************************/ /* Spad */ /********************************************************************/ diff --git a/src/discoh/bank/fd_bank_tile.c b/src/discoh/bank/fd_bank_tile.c index cef49085e1..affd9f2690 100644 --- a/src/discoh/bank/fd_bank_tile.c +++ b/src/discoh/bank/fd_bank_tile.c @@ -1,6 +1,7 @@ #include "fd_bank_abi.h" #include "../../disco/tiles.h" +#include "../../disco/topo/fd_topo.h" #include "../../disco/pack/fd_pack.h" #include "../../disco/pack/fd_pack_cost.h" #include "../../ballet/blake3/fd_blake3.h" diff --git a/src/discoh/poh/fd_poh_tile.c b/src/discoh/poh/fd_poh_tile.c index 400b419c2c..41a7b92eb7 100644 --- a/src/discoh/poh/fd_poh_tile.c +++ b/src/discoh/poh/fd_poh_tile.c @@ -307,6 +307,7 @@ will always be 420,000. */ #include "../../disco/tiles.h" +#include "../../disco/topo/fd_topo.h" #include "../../disco/bundle/fd_bundle_crank.h" #include "../../disco/pack/fd_pack.h" #include "../../ballet/sha256/fd_sha256.h" diff --git a/src/discoh/resolv/fd_resolv_tile.c b/src/discoh/resolv/fd_resolv_tile.c index 36c2c6d5c6..b45883df9b 100644 --- a/src/discoh/resolv/fd_resolv_tile.c +++ b/src/discoh/resolv/fd_resolv_tile.c @@ -1,8 +1,9 @@ #include "../bank/fd_bank_abi.h" #include "../../disco/tiles.h" +#include "../../disco/fd_txn_m_t.h" +#include "../../disco/topo/fd_topo.h" #include "../../disco/metrics/fd_metrics.h" -#include "../../flamenco/runtime/fd_system_ids.h" #include "../../flamenco/runtime/fd_system_ids_pp.h" #if FD_HAS_AVX diff --git a/src/discoh/store/fd_store_tile.c b/src/discoh/store/fd_store_tile.c index a2cf2e91c1..7736beb60f 100644 --- a/src/discoh/store/fd_store_tile.c +++ b/src/discoh/store/fd_store_tile.c @@ -1,4 +1,5 @@ #include "../../disco/tiles.h" +#include "../../disco/topo/fd_topo.h" #include "../../disco/metrics/fd_metrics.h" typedef struct { diff --git a/src/flamenco/fd_flamenco_base.h b/src/flamenco/fd_flamenco_base.h index e3790a5004..0b1f1bb50f 100644 --- a/src/flamenco/fd_flamenco_base.h +++ b/src/flamenco/fd_flamenco_base.h @@ -72,6 +72,9 @@ fd_base58_enc_64_fmt( char * out, /* Forward declarations */ +struct fd_bank; +typedef struct fd_bank fd_bank_t; + struct fd_exec_slot_ctx; typedef struct fd_exec_slot_ctx fd_exec_slot_ctx_t; diff --git a/src/flamenco/rewards/fd_rewards.c b/src/flamenco/rewards/fd_rewards.c index a192912425..a44e85a113 100644 --- a/src/flamenco/rewards/fd_rewards.c +++ b/src/flamenco/rewards/fd_rewards.c @@ -55,19 +55,21 @@ validator( fd_inflation_t const * inflation, double year) { https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank.rs#L2095 */ static FD_FN_CONST ulong -get_inflation_start_slot( fd_exec_slot_ctx_t * slot_ctx ) { - ulong devnet_and_testnet = FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, devnet_and_testnet ) ? fd_bank_features_query( slot_ctx->bank )->devnet_and_testnet : ULONG_MAX; +get_inflation_start_slot( fd_bank_t const * bank ) { + ulong devnet_and_testnet = FD_FEATURE_ACTIVE_BANK( bank, devnet_and_testnet ) + ? fd_bank_features_query( bank )->devnet_and_testnet + : ULONG_MAX; ulong enable = ULONG_MAX; - if( FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, full_inflation_vote ) && - FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, full_inflation_enable ) ) { - enable = fd_bank_features_query( slot_ctx->bank )->full_inflation_enable; + if( FD_FEATURE_ACTIVE_BANK( bank, full_inflation_vote ) && + FD_FEATURE_ACTIVE_BANK( bank, full_inflation_enable ) ) { + enable = fd_bank_features_query( bank )->full_inflation_enable; } ulong min_slot = fd_ulong_min( enable, devnet_and_testnet ); if( min_slot == ULONG_MAX ) { - if( FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, pico_inflation ) ) { - min_slot = fd_bank_features_query( slot_ctx->bank )->pico_inflation; + if( FD_FEATURE_ACTIVE_BANK( bank, pico_inflation ) ) { + min_slot = fd_bank_features_query( bank )->pico_inflation; } else { min_slot = 0; } @@ -77,27 +79,26 @@ get_inflation_start_slot( fd_exec_slot_ctx_t * slot_ctx ) { /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank.rs#L2110 */ static ulong -get_inflation_num_slots( fd_exec_slot_ctx_t * slot_ctx, - fd_epoch_schedule_t const * epoch_schedule, - ulong slot ) { - ulong inflation_activation_slot = get_inflation_start_slot( slot_ctx ); - ulong inflation_start_slot = fd_epoch_slot0( epoch_schedule, - fd_ulong_sat_sub( fd_slot_to_epoch( epoch_schedule, +get_inflation_num_slots( fd_bank_t const * bank, + ulong slot ) { + fd_epoch_schedule_t epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( bank ) ); + ulong inflation_activation_slot = get_inflation_start_slot( bank ); + ulong inflation_start_slot = fd_epoch_slot0( &epoch_schedule, + fd_ulong_sat_sub( fd_slot_to_epoch( &epoch_schedule, inflation_activation_slot, NULL ), 1UL ) ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, slot, NULL ); + ulong epoch = fd_slot_to_epoch( &epoch_schedule, slot, NULL ); - return fd_epoch_slot0( epoch_schedule, epoch ) - inflation_start_slot; + return fd_epoch_slot0( &epoch_schedule, epoch ) - inflation_start_slot; } /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank.rs#L2121 */ static double -slot_in_year_for_inflation( fd_exec_slot_ctx_t * slot_ctx ) { - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - - ulong num_slots = get_inflation_num_slots( slot_ctx, epoch_schedule, fd_bank_slot_get( slot_ctx->bank ) ); - return (double)num_slots / (double)fd_bank_slots_per_year_get( slot_ctx->bank ); +slot_in_year_for_inflation( fd_bank_t const * bank ) { + ulong num_slots = get_inflation_num_slots( bank, fd_bank_slot_get( bank ) ); + return (double)num_slots / (double)fd_bank_slots_per_year_get( bank ); } /* For a given stake and vote_state, calculate how many points were earned (credits * stake) and new value @@ -276,23 +277,25 @@ get_slots_in_epoch( ulong epoch, /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank.rs#L2082 */ static double -epoch_duration_in_years( fd_exec_slot_ctx_t * slot_ctx, - ulong prev_epoch ) { - ulong slots_in_epoch = get_slots_in_epoch( prev_epoch, fd_bank_epoch_schedule_query( slot_ctx->bank ) ); - return (double)slots_in_epoch / (double)fd_bank_slots_per_year_get( slot_ctx->bank ); +epoch_duration_in_years( fd_bank_t const * bank, + ulong prev_epoch ) { + fd_epoch_schedule_t epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( bank ) ); + ulong slots_in_epoch = get_slots_in_epoch( prev_epoch, &epoch_schedule ); + return (double)slots_in_epoch / (double)fd_bank_slots_per_year_get( bank ); } /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank.rs#L2128 */ static void -calculate_previous_epoch_inflation_rewards( fd_exec_slot_ctx_t * slot_ctx, +calculate_previous_epoch_inflation_rewards( fd_bank_t const * bank, ulong prev_epoch_capitalization, ulong prev_epoch, fd_prev_epoch_inflation_rewards_t * rewards ) { - double slot_in_year = slot_in_year_for_inflation( slot_ctx ); + double slot_in_year = slot_in_year_for_inflation( bank ); - rewards->validator_rate = validator( fd_bank_inflation_query( slot_ctx->bank ), slot_in_year ); - rewards->foundation_rate = foundation( fd_bank_inflation_query( slot_ctx->bank ), slot_in_year ); - rewards->prev_epoch_duration_in_years = epoch_duration_in_years( slot_ctx, prev_epoch ); + rewards->validator_rate = validator( fd_bank_inflation_query( bank ), slot_in_year ); + rewards->foundation_rate = foundation( fd_bank_inflation_query( bank ), slot_in_year ); + rewards->prev_epoch_duration_in_years = epoch_duration_in_years( bank, prev_epoch ); rewards->validator_rewards = (ulong)(rewards->validator_rate * (double)prev_epoch_capitalization * rewards->prev_epoch_duration_in_years); FD_LOG_DEBUG(( "Rewards %lu, Rate %.16f, Duration %.18f Capitalization %lu Slot in year %.16f", rewards->validator_rewards, rewards->validator_rate, rewards->prev_epoch_duration_in_years, prev_epoch_capitalization, slot_in_year )); } @@ -377,8 +380,7 @@ calculate_reward_points_partitioned( fd_exec_slot_ctx_t * slot_ctx, ulong rewards, fd_point_value_t * result, fd_tpool_t * tpool, - fd_epoch_info_t * temp_info, - fd_spad_t * runtime_spad ) { + fd_epoch_info_t * temp_info ) { uint128 points = 0; ulong minimum_stake_delegation = get_minimum_stake_delegation( slot_ctx ); @@ -388,11 +390,9 @@ calculate_reward_points_partitioned( fd_exec_slot_ctx_t * slot_ctx, ulong new_warmup_cooldown_rate_epoch_val = 0UL; ulong * new_warmup_cooldown_rate_epoch = &new_warmup_cooldown_rate_epoch_val; int is_some = fd_new_warmup_cooldown_rate_epoch( - fd_bank_slot_get( slot_ctx->bank ), - slot_ctx->funk, - slot_ctx->funk_txn, - runtime_spad, + fd_bank_sysvar_cache_query( slot_ctx->bank ), fd_bank_features_query( slot_ctx->bank ), + fd_bank_slot_get( slot_ctx->bank ), new_warmup_cooldown_rate_epoch, _err ); if( FD_UNLIKELY( !is_some ) ) { @@ -607,11 +607,9 @@ calculate_stake_vote_rewards( fd_exec_slot_ctx_t * slot_ct ulong new_warmup_cooldown_rate_epoch_val = 0UL; ulong * new_warmup_cooldown_rate_epoch = &new_warmup_cooldown_rate_epoch_val; int is_some = fd_new_warmup_cooldown_rate_epoch( - fd_bank_slot_get( slot_ctx->bank ), - slot_ctx->funk, - slot_ctx->funk_txn, - runtime_spad, + fd_bank_sysvar_cache_query( slot_ctx->bank ), fd_bank_features_query( slot_ctx->bank ), + fd_bank_slot_get( slot_ctx->bank ), new_warmup_cooldown_rate_epoch, _err ); if( FD_UNLIKELY( !is_some ) ) { @@ -701,8 +699,11 @@ calculate_validator_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * * exec_spads, ulong exec_spad_cnt, fd_spad_t * runtime_spad ) { - /* https://github.com/firedancer-io/solana/blob/dab3da8e7b667d7527565bddbdbecf7ec1fb868e/runtime/src/bank.rs#L2759-L2786 */ - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); + /* FIXME the reflinks here heavily diverged from upstream Agave */ + + /* https://github.com/firedancer-io/solana/blob/dab3da8e7b667d7527565bddbdbecf7ec1fb868e/runtime/src/bank.rs#L2759-L2786 */ + fd_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( slot_ctx->bank ); + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( sysvar_cache ); if( FD_UNLIKELY( !stake_history ) ) { FD_LOG_ERR(( "Unable to read and decode stake history sysvar" )); } @@ -713,8 +714,7 @@ calculate_validator_rewards( fd_exec_slot_ctx_t * slot_ctx, rewards, &result->point_value, tpool, - temp_info, - runtime_spad ); + temp_info ); /* Calculate the stake and vote rewards for each account */ calculate_stake_vote_rewards( slot_ctx, @@ -727,6 +727,8 @@ calculate_validator_rewards( fd_exec_slot_ctx_t * slot_ctx, exec_spads, exec_spad_cnt, runtime_spad ); + + fd_sysvar_stake_history_leave_const( sysvar_cache, stake_history ); } /* Calculate the number of blocks required to distribute rewards to all stake accounts. @@ -822,7 +824,7 @@ calculate_rewards_for_partitioning( fd_exec_slot_ctx_t * slot_ /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L227 */ fd_prev_epoch_inflation_rewards_t rewards; - calculate_previous_epoch_inflation_rewards( slot_ctx, + calculate_previous_epoch_inflation_rewards( slot_ctx->bank, fd_bank_capitalization_get( slot_ctx->bank ), prev_epoch, &rewards ); @@ -839,10 +841,13 @@ calculate_rewards_for_partitioning( fd_exec_slot_ctx_t * slot_ runtime_spad ); fd_stake_reward_calculation_t * stake_reward_calculation = &validator_result->calculate_stake_vote_rewards_result.stake_reward_calculation; - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong num_partitions = get_reward_distribution_num_blocks( epoch_schedule, - fd_bank_slot_get( slot_ctx->bank ), - stake_reward_calculation->stake_rewards_len ); + fd_epoch_schedule_t const epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + + ulong num_partitions = get_reward_distribution_num_blocks( + &epoch_schedule, + fd_bank_slot_get( slot_ctx->bank ), + stake_reward_calculation->stake_rewards_len ); hash_rewards_into_partitions( stake_reward_calculation, parent_blockhash, num_partitions, @@ -984,13 +989,13 @@ distribute_epoch_reward_to_stake_acc( fd_exec_slot_ctx_t * slot_ctx, /* Sets the epoch reward status to inactive, and destroys any allocated state associated with the active state. */ static void -set_epoch_reward_status_inactive( fd_exec_slot_ctx_t * slot_ctx ) { - fd_epoch_reward_status_global_t * epoch_reward_status = fd_bank_epoch_reward_status_locking_modify( slot_ctx->bank ); +set_epoch_reward_status_inactive( fd_bank_t * bank ) { + fd_epoch_reward_status_global_t * epoch_reward_status = fd_bank_epoch_reward_status_locking_modify( bank ); if( epoch_reward_status->discriminant == fd_epoch_reward_status_enum_Active ) { FD_LOG_NOTICE(( "Done partitioning rewards for current epoch" )); } epoch_reward_status->discriminant = fd_epoch_reward_status_enum_Inactive; - fd_bank_epoch_reward_status_end_locking_modify( slot_ctx->bank ); + fd_bank_epoch_reward_status_end_locking_modify( bank ); } /* Sets the epoch reward status to active. @@ -1038,8 +1043,7 @@ set_epoch_reward_status_active( fd_exec_slot_ctx_t * slot_ctx, static void distribute_epoch_rewards_in_partition( fd_partitioned_stake_rewards_dlist_t * partition, fd_stake_reward_t * pool, - fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ) { + fd_exec_slot_ctx_t * slot_ctx ) { ulong lamports_distributed = 0UL; ulong lamports_burned = 0UL; @@ -1061,8 +1065,7 @@ distribute_epoch_rewards_in_partition( fd_partitioned_stake_rewards_dlist_t * pa /* Update the epoch rewards sysvar with the amount distributed and burnt */ fd_sysvar_epoch_rewards_distribute( slot_ctx, - lamports_distributed + lamports_burned, - runtime_spad ); + lamports_distributed + lamports_burned ); FD_LOG_DEBUG(( "lamports burned: %lu, lamports distributed: %lu", lamports_burned, lamports_distributed )); @@ -1073,15 +1076,7 @@ distribute_epoch_rewards_in_partition( fd_partitioned_stake_rewards_dlist_t * pa https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank/partitioned_epoch_rewards/distribution.rs#L42 */ void -fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, - fd_tpool_t * tpool, - fd_spad_t * * exec_spads, - ulong exec_spad_cnt, - fd_spad_t * runtime_spad ) { - - (void)tpool; - (void)exec_spads; - (void)exec_spad_cnt; +fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx ) { fd_epoch_reward_status_global_t const * epoch_reward_status = fd_bank_epoch_reward_status_locking_query( slot_ctx->bank ); @@ -1104,10 +1099,10 @@ fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, ulong distribution_starting_block_height = status->distribution_starting_block_height; ulong distribution_end_exclusive = distribution_starting_block_height + status->partitioned_stake_rewards.partitions_len; - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), NULL ); + fd_epoch_schedule_t epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + ulong epoch = fd_slot_to_epoch( &epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), NULL ); - if( FD_UNLIKELY( get_slots_in_epoch( epoch, epoch_schedule ) <= status->partitioned_stake_rewards.partitions_len ) ) { + if( FD_UNLIKELY( get_slots_in_epoch( epoch, &epoch_schedule ) <= status->partitioned_stake_rewards.partitions_len ) ) { FD_LOG_ERR(( "Should not be distributing rewards" )); } @@ -1115,16 +1110,15 @@ fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, ulong partition_index = height - distribution_starting_block_height; distribute_epoch_rewards_in_partition( &partitions[ partition_index ], pool, - slot_ctx, - runtime_spad ); + slot_ctx ); } fd_bank_epoch_reward_status_end_locking_query( slot_ctx->bank ); /* If we have finished distributing rewards, set the status to inactive */ if( fd_ulong_sat_add( height, 1UL ) >= distribution_end_exclusive ) { - set_epoch_reward_status_inactive( slot_ctx ); - fd_sysvar_epoch_rewards_set_inactive( slot_ctx, runtime_spad ); + set_epoch_reward_status_inactive( slot_ctx->bank ); + fd_sysvar_epoch_rewards_set_inactive( slot_ctx ); } } @@ -1183,10 +1177,11 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * * exec_spads, ulong exec_spad_cnt, fd_spad_t * runtime_spad ) { - fd_sysvar_epoch_rewards_t * epoch_rewards = fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); - if( FD_UNLIKELY( epoch_rewards == NULL ) ) { + fd_sysvar_epoch_rewards_t epoch_rewards_; + fd_sysvar_epoch_rewards_t const * epoch_rewards = fd_sysvar_epoch_rewards_read( fd_bank_sysvar_cache_query( slot_ctx->bank ), &epoch_rewards_ ); + if( FD_UNLIKELY( !epoch_rewards ) ) { FD_LOG_NOTICE(( "Failed to read or decode epoch rewards sysvar - may not have been created yet" )); - set_epoch_reward_status_inactive( slot_ctx ); + set_epoch_reward_status_inactive( slot_ctx->bank ); return; } @@ -1206,24 +1201,25 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, https://github.com/anza-xyz/agave/blob/2316fea4c0852e59c071f72d72db020017ffd7d0/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L566 */ FD_LOG_NOTICE(( "epoch rewards is active" )); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), NULL ); - ulong rewarded_epoch = fd_ulong_sat_sub( epoch, 1UL ); + ulong const slot = fd_bank_slot_get( slot_ctx->bank ); + ulong const epoch = fd_bank_epoch_get( slot_ctx->bank ); + ulong const rewarded_epoch = fd_ulong_sat_sub( epoch, 1UL ); + fd_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( slot_ctx->bank ); int _err[1] = {0}; - ulong * new_warmup_cooldown_rate_epoch = fd_spad_alloc( runtime_spad, alignof(ulong), sizeof(ulong) ); - int is_some = fd_new_warmup_cooldown_rate_epoch( fd_bank_slot_get( slot_ctx->bank ), - slot_ctx->funk, - slot_ctx->funk_txn, - runtime_spad, - fd_bank_features_query( slot_ctx->bank ), - new_warmup_cooldown_rate_epoch, - _err ); + ulong new_warmup_cooldown_rate_epoch_; + ulong * new_warmup_cooldown_rate_epoch = &new_warmup_cooldown_rate_epoch_; + int is_some = fd_new_warmup_cooldown_rate_epoch( + sysvar_cache, + fd_bank_features_query( slot_ctx->bank ), + slot, + new_warmup_cooldown_rate_epoch, + _err ); if( FD_UNLIKELY( !is_some ) ) { new_warmup_cooldown_rate_epoch = NULL; } - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( sysvar_cache ); if( FD_UNLIKELY( !stake_history ) ) { FD_LOG_ERR(( "Unable to read and decode stake history sysvar" )); } @@ -1303,6 +1299,6 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, epoch_rewards->distribution_starting_block_height, &stake_rewards_by_partition->partitioned_stake_rewards ); } else { - set_epoch_reward_status_inactive( slot_ctx ); + set_epoch_reward_status_inactive( slot_ctx->bank ); } } diff --git a/src/flamenco/rewards/fd_rewards.h b/src/flamenco/rewards/fd_rewards.h index 26668d91bc..39fffef999 100644 --- a/src/flamenco/rewards/fd_rewards.h +++ b/src/flamenco/rewards/fd_rewards.h @@ -52,11 +52,7 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ); void -fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, - fd_tpool_t * tpool, - fd_spad_t * * exec_spads, - ulong exec_spad_cnt, - fd_spad_t * runtime_spad ); +fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx ); FD_PROTOTYPES_END diff --git a/src/flamenco/runtime/Local.mk b/src/flamenco/runtime/Local.mk index 3f30ffe43e..67e26429de 100644 --- a/src/flamenco/runtime/Local.mk +++ b/src/flamenco/runtime/Local.mk @@ -8,6 +8,11 @@ $(call add-objs,fd_txn_account,fd_flamenco) $(call add-hdrs,fd_bank_hash_cmp.h fd_rwseq_lock.h) $(call add-objs,fd_bank_hash_cmp,fd_flamenco) +$(call add-hdrs,fd_blockhashes.h) +$(call add-objs,fd_blockhashes,fd_flamenco) +$(call make-unit-test,test_blockhashes,test_blockhashes,fd_flamenco fd_util) +$(call run-unit-test,test_blockhashes) + $(call add-hdrs,fd_blockstore.h fd_rwseq_lock.h) $(call add-objs,fd_blockstore,fd_flamenco) $(call make-unit-test,test_blockstore,test_blockstore, fd_flamenco fd_util fd_ballet,$(SECP256K1_LIBS)) diff --git a/src/flamenco/runtime/context/fd_exec_instr_ctx.h b/src/flamenco/runtime/context/fd_exec_instr_ctx.h index 9a06a9c760..f72667356c 100644 --- a/src/flamenco/runtime/context/fd_exec_instr_ctx.h +++ b/src/flamenco/runtime/context/fd_exec_instr_ctx.h @@ -3,6 +3,7 @@ #include "../info/fd_instr_info.h" #include "../fd_executor_err.h" +#include "../sysvar/fd_sysvar_cache.h" /* Avoid circular include dependency with forward declaration */ struct fd_borrowed_account; @@ -15,6 +16,7 @@ struct fd_exec_instr_ctx { ulong magic; /* ==FD_EXEC_INSTR_CTX_MAGIC */ fd_instr_info_t const * instr; /* The instruction info for this instruction */ fd_exec_txn_ctx_t * txn_ctx; /* The transaction context for this instruction */ + fd_sysvar_cache_t const * sysvar_cache; /* Most instructions log the base58 program id multiple times, so it's convenient to compute it once and reuse it. */ diff --git a/src/flamenco/runtime/context/fd_exec_slot_ctx.c b/src/flamenco/runtime/context/fd_exec_slot_ctx.c index d90611d2c4..ab90cb9748 100644 --- a/src/flamenco/runtime/context/fd_exec_slot_ctx.c +++ b/src/flamenco/runtime/context/fd_exec_slot_ctx.c @@ -1,5 +1,6 @@ #include "fd_exec_slot_ctx.h" #include "../sysvar/fd_sysvar_epoch_schedule.h" +#include "../sysvar/fd_sysvar_last_restart_slot.h" #include "../program/fd_vote_program.h" #include "../../../ballet/lthash/fd_lthash.h" @@ -115,8 +116,6 @@ recover_clock( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { n; n = fd_vote_accounts_pair_global_t_map_successor( vote_accounts_pool, n ) ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { - /* Extract vote timestamp of account */ int err; @@ -157,7 +156,6 @@ recover_clock( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { if( slot != 0 || n->elem.stake != 0 ) { fd_vote_record_timestamp_vote_with_slot( &n->elem.key, timestamp, slot, slot_ctx->bank ); } - } FD_SPAD_FRAME_END; } fd_bank_stakes_end_locking_query( slot_ctx->bank ); @@ -186,39 +184,11 @@ fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx, /* Index vote accounts */ /* Block Hash Queue */ - - fd_block_hash_queue_global_t * bhq = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0]; - uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)bhq + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) ); - uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() ); - - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 301 ) ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = NULL; - - bhq->last_hash_index = old_bank->blockhash_queue.last_hash_index; - - fd_hash_t const * last_hash = fd_block_hash_vec_last_hash_join( &old_bank->blockhash_queue ); - - if( last_hash ) { - fd_memcpy( last_hash_mem, last_hash, sizeof(fd_hash_t) ); - } else { - fd_memset( last_hash_mem, 0, sizeof(fd_hash_t) ); - } - bhq->last_hash_offset = (ulong)last_hash_mem - (ulong)bhq; - - fd_hash_hash_age_pair_t const * ages = fd_block_hash_vec_ages_join( &old_bank->blockhash_queue ); - - for( ulong i=0UL; iblockhash_queue.ages_len; i++ ) { - fd_hash_hash_age_pair_t const * elem = &ages[i]; - fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( ages_pool ); - node->elem = *elem; - fd_hash_hash_age_pair_t_map_insert( ages_pool, &ages_root, node ); + { + fd_blockhashes_t * bhq = fd_bank_block_hash_queue_modify( slot_ctx->bank ); + FD_TEST( fd_blockhashes_recover( bhq, &old_bank->blockhash_queue ) ); } - fd_block_hash_queue_ages_pool_update( bhq, ages_pool ); - fd_block_hash_queue_ages_root_update( bhq, ages_root ); - - bhq->max_age = old_bank->blockhash_queue.max_age; - /* Bank Hash */ fd_bank_bank_hash_set( slot_ctx->bank, old_bank->hash ); @@ -308,8 +278,10 @@ fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx, /* PoH */ - if( last_hash ) { - fd_bank_poh_set( slot_ctx->bank, *last_hash ); + { + fd_blockhashes_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank ); + fd_hash_t const * last_hash = fd_blockhashes_peek_last( bhq ); + if( last_hash ) fd_bank_poh_set( slot_ctx->bank, *last_hash ); } /* Prev Bank Hash */ @@ -318,11 +290,11 @@ fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx, /* Epoch Schedule */ - fd_bank_epoch_schedule_set( slot_ctx->bank, old_bank->epoch_schedule ); + fd_sysvar_epoch_schedule_write( slot_ctx, &old_bank->epoch_schedule ); /* Rent */ - fd_bank_rent_set( slot_ctx->bank, old_bank->rent_collector.rent ); + fd_sysvar_rent_write( slot_ctx, &old_bank->rent_collector.rent ); /* Last Restart Slot */ @@ -333,26 +305,10 @@ fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx, To find the last restart slot, take the highest hard fork slot number that is less or equal than the current slot number. (There might be some hard forks in the future, ignore these) */ - do { - fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank ); - last_restart_slot->slot = 0UL; - - if( FD_UNLIKELY( old_bank->hard_forks.hard_forks_len == 0 ) ) { - /* SIMD-0047: The first restart slot should be `0` */ - break; - } - - fd_slot_pair_t const * head = fd_hard_forks_hard_forks_join( &old_bank->hard_forks ); - fd_slot_pair_t const * tail = head + old_bank->hard_forks.hard_forks_len - 1UL; - - for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) { - if( pair->slot <= fd_bank_slot_get( slot_ctx->bank ) ) { - fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_bank_last_restart_slot_modify( slot_ctx->bank ); - last_restart_slot->slot = pair->slot; - break; - } - } - } while (0); + ulong const slot = fd_bank_slot_get( slot_ctx->bank ); + fd_sol_sysvar_last_restart_slot_t lrs_sysvar = { fd_sysvar_last_restart_slot_derive( &old_bank->hard_forks, slot ) }; + fd_bank_last_restart_slot_set( slot_ctx->bank, lrs_sysvar ); + fd_sysvar_last_restart_slot_update( slot_ctx, lrs_sysvar.slot ); /* FIXME: Remove the magic number here. */ fd_clock_timestamp_votes_global_t * clock_timestamp_votes = fd_bank_clock_timestamp_votes_locking_modify( slot_ctx->bank ); @@ -368,8 +324,7 @@ fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx, /* Move EpochStakes */ do { - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), NULL ); + ulong epoch = fd_bank_epoch_get( slot_ctx->bank ); /* We need to save the vote accounts for the current epoch and the next epoch as it is used to calculate the leader schedule at the epoch diff --git a/src/flamenco/runtime/context/fd_exec_slot_ctx.h b/src/flamenco/runtime/context/fd_exec_slot_ctx.h index 4f70838ba0..e27947ec32 100644 --- a/src/flamenco/runtime/context/fd_exec_slot_ctx.h +++ b/src/flamenco/runtime/context/fd_exec_slot_ctx.h @@ -1,15 +1,8 @@ #ifndef HEADER_fd_src_flamenco_runtime_context_fd_exec_slot_ctx_h #define HEADER_fd_src_flamenco_runtime_context_fd_exec_slot_ctx_h -#include "../fd_blockstore.h" -#include "../../../funk/fd_funk.h" -#include "../../../util/rng/fd_rng.h" -#include "../../../util/wksp/fd_wksp.h" - #include "../../types/fd_types.h" #include "../fd_txncache.h" -#include "../fd_acc_mgr.h" -#include "../fd_bank_hash_cmp.h" #include "../fd_bank.h" /* fd_exec_slot_ctx_t is the context that stays constant during all diff --git a/src/flamenco/runtime/context/fd_exec_txn_ctx.h b/src/flamenco/runtime/context/fd_exec_txn_ctx.h index bc7abd6025..312c19f1a5 100644 --- a/src/flamenco/runtime/context/fd_exec_txn_ctx.h +++ b/src/flamenco/runtime/context/fd_exec_txn_ctx.h @@ -70,6 +70,7 @@ struct fd_exec_txn_ctx { /* All pointers starting here are valid local joins in txn execution. */ fd_features_t features; + fd_sysvar_cache_t const * restrict sysvar_cache; fd_txncache_t * status_cache; int enable_exec_recording; fd_bank_hash_cmp_t * bank_hash_cmp; diff --git a/src/flamenco/runtime/fd_bank.c b/src/flamenco/runtime/fd_bank.c index bba83d45d2..55f4081b3e 100644 --- a/src/flamenco/runtime/fd_bank.c +++ b/src/flamenco/runtime/fd_bank.c @@ -1,5 +1,6 @@ #include "fd_bank.h" -#include "../../util/fd_util_base.h" +#include "sysvar/fd_sysvar_cache.h" +#include "sysvar/fd_sysvar_epoch_schedule.h" ulong fd_bank_align( void ) { @@ -72,7 +73,7 @@ fd_bank_footprint( void ) { #define HAS_LOCK_0(type, name) \ type const * \ - fd_bank_##name##_query( fd_bank_t * bank ) { \ + fd_bank_##name##_query( fd_bank_t const * bank ) { \ return (type const *)fd_type_pun_const( bank->name ); \ } \ type * \ @@ -107,7 +108,7 @@ fd_bank_footprint( void ) { FD_STORE( type, bank->name, value ); \ } \ type \ - fd_bank_##name##_get( fd_bank_t * bank ) { \ + fd_bank_##name##_get( fd_bank_t const * bank ) { \ type val = FD_LOAD( type, bank->name ); \ return val; \ } @@ -397,7 +398,7 @@ fd_banks_init_bank( fd_banks_t * banks, ulong slot ) { memset( bank, 0, fd_bank_footprint() ); ulong null_idx = fd_banks_pool_idx_null( bank_pool ); - bank->slot = slot; + bank->slot_ = slot; bank->next = null_idx; bank->parent_idx = null_idx; bank->child_idx = null_idx; @@ -506,7 +507,7 @@ fd_banks_clone_from_parent( fd_banks_t * banks, ulong null_idx = fd_banks_pool_idx_null( bank_pool ); - new_bank->slot = slot; + new_bank->slot_ = slot; new_bank->next = null_idx; new_bank->parent_idx = null_idx; new_bank->child_idx = null_idx; @@ -606,7 +607,7 @@ fd_banks_publish( fd_banks_t * banks, ulong slot ) { return NULL; } - fd_bank_t * head = fd_banks_map_ele_remove( bank_map, &old_root->slot, NULL, bank_pool ); + fd_bank_t * head = fd_banks_map_ele_remove( bank_map, &old_root->slot_, NULL, bank_pool ); head->next = fd_banks_pool_idx_null( bank_pool ); fd_bank_t * tail = head; @@ -619,10 +620,11 @@ fd_banks_publish( fd_banks_t * banks, ulong slot ) { /* Remove the child from the map first and push onto the frontier list that needs to be iterated through */ - tail->next = fd_banks_map_idx_remove( bank_map, - &child->slot, - fd_banks_pool_idx_null( bank_pool ), - bank_pool ); + tail->next = fd_banks_map_idx_remove( + bank_map, + &child->slot_, + fd_banks_pool_idx_null( bank_pool ), + bank_pool ); tail = fd_banks_pool_ele( bank_pool, tail->next ); tail->next = fd_banks_pool_idx_null( bank_pool ); @@ -704,3 +706,10 @@ fd_bank_clear_bank( fd_bank_t * bank ) { #undef HAS_COW_0 #undef HAS_COW_1 } + +ulong +fd_bank_epoch_get( fd_bank_t const * bank ) { + fd_epoch_schedule_t epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( bank ) ); + return fd_slot_to_epoch( &epoch_schedule, fd_bank_slot_get( bank ), NULL ); +} diff --git a/src/flamenco/runtime/fd_bank.h b/src/flamenco/runtime/fd_bank.h index a2fbff9788..2a6f76ad84 100644 --- a/src/flamenco/runtime/fd_bank.h +++ b/src/flamenco/runtime/fd_bank.h @@ -5,6 +5,8 @@ #include "../leaders/fd_leaders.h" #include "../features/fd_features.h" #include "../fd_rwlock.h" +#include "fd_blockhashes.h" +#include "sysvar/fd_sysvar_cache.h" FD_PROTOTYPES_BEGIN @@ -132,7 +134,7 @@ FD_PROTOTYPES_BEGIN X(fd_clock_timestamp_votes_global_t, clock_timestamp_votes, 5000000UL, 128UL, 1, 1 ) /* TODO: This needs to get sized out */ \ X(fd_account_keys_global_t, stake_account_keys, 100000000UL, 128UL, 1, 1 ) /* Supports roughly 3M stake accounts */ \ X(fd_account_keys_global_t, vote_account_keys, 3200000UL, 128UL, 1, 1 ) /* Supports roughly 100k vote accounts */ \ - X(fd_block_hash_queue_global_t, block_hash_queue, 50000UL, 128UL, 0, 0 ) /* Block hash queue */ \ + X(fd_blockhashes_t, block_hash_queue, sizeof(fd_blockhashes_t), alignof(fd_blockhashes_t), 0, 0 ) /* Block hash queue */ \ X(fd_fee_rate_governor_t, fee_rate_governor, sizeof(fd_fee_rate_governor_t), alignof(fd_fee_rate_governor_t), 0, 0 ) /* Fee rate governor */ \ X(ulong, capitalization, sizeof(ulong), alignof(ulong), 0, 0 ) /* Capitalization */ \ X(ulong, lamports_per_signature, sizeof(ulong), alignof(ulong), 0, 0 ) /* Lamports per signature */ \ @@ -167,9 +169,8 @@ FD_PROTOTYPES_BEGIN X(fd_hash_t, bank_hash, sizeof(fd_hash_t), alignof(fd_hash_t), 0, 0 ) /* Bank hash */ \ X(fd_hash_t, prev_bank_hash, sizeof(fd_hash_t), alignof(fd_hash_t), 0, 0 ) /* Previous bank hash */ \ X(fd_hash_t, genesis_hash, sizeof(fd_hash_t), alignof(fd_hash_t), 0, 0 ) /* Genesis hash */ \ - X(fd_epoch_schedule_t, epoch_schedule, sizeof(fd_epoch_schedule_t), alignof(fd_epoch_schedule_t), 0, 0 ) /* Epoch schedule */ \ - X(fd_rent_t, rent, sizeof(fd_rent_t), alignof(fd_rent_t), 0, 0 ) /* Rent */ \ X(fd_slot_lthash_t, lthash, sizeof(fd_slot_lthash_t), alignof(fd_slot_lthash_t), 0, 0 ) /* LTHash */ \ + X(fd_sysvar_cache_t, sysvar_cache, FD_SYSVAR_CACHE_FOOTPRINT, FD_SYSVAR_CACHE_ALIGN, 0, 0 ) /* Sysvar cache */ \ X(fd_vote_accounts_global_t, next_epoch_stakes, 200000000UL, 128UL, 1, 1 ) /* Next epoch stakes, ~4K per account * 50k vote accounts */ \ /* These are the stakes that determine the leader */ \ /* schedule for the upcoming epoch. If we are executing */ \ @@ -286,7 +287,7 @@ struct fd_bank { #define FD_BANK_HEADER_SIZE (40UL) /* Fields used for internal pool and bank management */ - ulong slot; /* slot this node is tracking, also the map key */ + ulong slot_; /* slot this node is tracking, also the map key */ ulong next; /* reserved for internal use by fd_pool_para, fd_map_chain_para and fd_banks_publish */ ulong parent_idx; /* index of the parent in the node pool */ ulong child_idx; /* index of the left-child in the node pool */ @@ -396,7 +397,7 @@ fd_bank_footprint( void ); #define MAP_NAME fd_banks_map #define MAP_ELE_T fd_bank_t -#define MAP_KEY slot +#define MAP_KEY slot_ #include "../../util/tmpl/fd_map_chain.c" #undef MAP_NAME #undef MAP_ELE_T @@ -438,12 +439,12 @@ typedef struct fd_banks fd_banks_t; void fd_bank_##name##_end_locking_modify( fd_bank_t * bank ); #define HAS_LOCK_0(type, name) \ - type const * fd_bank_##name##_query( fd_bank_t * bank ); \ + type const * fd_bank_##name##_query( fd_bank_t const * bank ); \ type * fd_bank_##name##_modify( fd_bank_t * bank ); #define X(type, name, footprint, align, cow, has_lock) \ void fd_bank_##name##_set( fd_bank_t * bank, type value ); \ - type fd_bank_##name##_get( fd_bank_t * bank ); \ + type fd_bank_##name##_get( fd_bank_t const * bank ); \ HAS_LOCK_##has_lock(type, name) FD_BANKS_ITER(X) #undef X @@ -452,10 +453,13 @@ FD_BANKS_ITER(X) #undef HAS_LOCK_1 static inline ulong -fd_bank_slot_get( fd_bank_t * bank ) { - return bank->slot; +fd_bank_slot_get( fd_bank_t const * bank ) { + return bank->slot_; } +ulong +fd_bank_epoch_get( fd_bank_t const * bank ); + /* Simple getters and setters for members of fd_banks_t.*/ static inline fd_bank_t * diff --git a/src/flamenco/runtime/fd_blockhashes.c b/src/flamenco/runtime/fd_blockhashes.c new file mode 100644 index 0000000000..e0e8e5c7b3 --- /dev/null +++ b/src/flamenco/runtime/fd_blockhashes.c @@ -0,0 +1,43 @@ +#include "fd_blockhashes.h" + +fd_blockhashes_t * +fd_blockhashes_recover( fd_blockhashes_t * blockhashes, + fd_block_hash_vec_global_t const * src ); + +static void +fd_blockhashes_pop( fd_blockhashes_t * blockhashes ) { + if( FD_UNLIKELY( fd_blockhash_deq_empty( blockhashes->d.deque ) ) ) return; + fd_blockhash_info_t * info = fd_blockhash_deq_pop_head_nocopy( blockhashes->d.deque ); + fd_blockhash_map_ele_remove( blockhashes->map, &info->hash, NULL, blockhashes->d.deque ); +} + +fd_blockhash_info_t * +fd_blockhashes_push( fd_blockhashes_t * blockhashes, + fd_hash_t const * hash ) { + if( FD_UNLIKELY( fd_blockhash_deq_full( blockhashes->d.deque ) ) ) { + fd_blockhashes_pop( blockhashes ); + } + + fd_blockhash_info_t * info = fd_blockhash_deq_push_tail_nocopy( blockhashes->d.deque ); + *info = (fd_blockhash_info_t) { .hash = *hash }; + + fd_blockhash_map_ele_insert( blockhashes->map, info, blockhashes->d.deque ); + + return info; +} + +FD_FN_PURE int +fd_blockhashes_check_age( fd_blockhashes_t const * blockhashes, + fd_hash_t const * blockhash, + ulong max_age ) { + fd_blockhash_info_t const * info = + fd_blockhash_map_ele_query_const( blockhashes->map, blockhash, NULL, blockhashes->d.deque ); + if( FD_UNLIKELY( !info ) ) return 0; + /* Derive distance from tail (end) */ + ulong base = ( blockhashes->d.end / FD_BLOCKHASHES_MAX ) * FD_BLOCKHASHES_MAX; + ulong idx = base + (ulong)( info - blockhashes->d.deque ); + long age = (long)( blockhashes->d.end - idx ); + if( age<0 ) age += FD_BLOCKHASHES_MAX; + FD_TEST( age>=0 ); + return (ulong)age <= max_age; +} diff --git a/src/flamenco/runtime/fd_blockhashes.h b/src/flamenco/runtime/fd_blockhashes.h new file mode 100644 index 0000000000..f1e800dc9f --- /dev/null +++ b/src/flamenco/runtime/fd_blockhashes.h @@ -0,0 +1,90 @@ +#ifndef HEADER_fd_src_flamenco_runtime_fd_blockhashes_h +#define HEADER_fd_src_flamenco_runtime_fd_blockhashes_h + +#include "../types/fd_types.h" +#include "../../funk/fd_funk_base.h" /* fd_funk_rec_key_hash1 */ + +/* fd_blockhashes.h provides a "blockhash queue" API. The blockhash + queue is a consensus-relevant data structure that is part of the slot + bank. + + See solana_accounts_db::blockhash_queue::BlockhashQueue. */ + +#define FD_BLOCKHASHES_MAX 301 + +/* See solana_accounts_db::blockhash_queue::HashInfo. */ + +struct fd_blockhash_info { + fd_hash_t hash; + fd_fee_calculator_t fee_calculator; + ushort next; +}; + +typedef struct fd_blockhash_info fd_blockhash_info_t; + +/* Declare a static size deque for the blockhash queue. */ + +#define DEQUE_NAME fd_blockhash_deq +#define DEQUE_T fd_blockhash_info_t +#define DEQUE_MAX FD_BLOCKHASHES_MAX +#include "../../util/tmpl/fd_deque.c" + +/* Declare a separately chained hash map over the blockhash queue. */ + +#define FD_BLOCKHASH_MAP_CHAIN_MAX (512UL) +#define FD_BLOCKHASH_MAP_FOOTPRINT (300UL) /* TODO */ + +#define MAP_NAME fd_blockhash_map +#define MAP_ELE_T fd_blockhash_info_t +#define MAP_KEY_T fd_hash_t +#define MAP_KEY hash +#define MAP_IDX_T ushort +#define MAP_NEXT next +#define MAP_KEY_EQ(k0,k1) fd_hash_eq( (k0), (k1) ) +#define MAP_KEY_HASH(k,s) fd_funk_rec_key_hash1( (k->uc), 0, (s) ) +#include "../../util/tmpl/fd_map_chain.c" + +/* fd_blockhashes_t is the class representing a blockhash queue. + It is a static size container housing sub-structures as plain old + struct members. Safe to declare as a local variable assuming the + stack is sufficiently sized. Entirely self-contained and position- + independent (safe to clone via fd_memcpy and safe to map into another + address space). */ + +struct fd_blockhashes { + + union { + fd_blockhash_map_t map[1]; + uchar map_mem[ FD_BLOCKHASH_MAP_FOOTPRINT ]; + }; + + fd_blockhash_deq_private_t d; + +}; + +typedef struct fd_blockhashes fd_blockhashes_t; + +FD_PROTOTYPES_BEGIN + +fd_blockhashes_t * +fd_blockhashes_recover( fd_blockhashes_t * blockhashes, + fd_block_hash_vec_global_t const * src ); + +fd_blockhash_info_t * +fd_blockhashes_push( fd_blockhashes_t * blockhashes, + fd_hash_t const * hash ); + +FD_FN_PURE int +fd_blockhashes_check_age( fd_blockhashes_t const * blockhashes, + fd_hash_t const * blockhash, + ulong max_age ); + +FD_FN_PURE static inline fd_hash_t const * +fd_blockhashes_peek_last( fd_blockhashes_t const * blockhashes ) { + if( FD_UNLIKELY( fd_blockhash_deq_empty( blockhashes->d.deque ) ) ) return 0; + return &fd_blockhash_deq_peek_tail_const( blockhashes->d.deque )->hash; +} + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_fd_blockhashes_h */ diff --git a/src/flamenco/runtime/fd_borrowed_account.c b/src/flamenco/runtime/fd_borrowed_account.c index b40c3d33be..2240233e0d 100644 --- a/src/flamenco/runtime/fd_borrowed_account.c +++ b/src/flamenco/runtime/fd_borrowed_account.c @@ -176,8 +176,8 @@ fd_borrowed_account_set_executable( fd_borrowed_account_t * borrowed_acct, /* To become executable an account must be rent exempt https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L1003-L1006 */ - fd_rent_t const * rent = fd_bank_rent_query( borrowed_acct->instr_ctx->txn_ctx->bank ); - if( FD_UNLIKELY( acct->vt->get_lamports( acct ) < fd_rent_exempt_minimum_balance( rent, acct->vt->get_data_len( acct ) ) ) ) { + fd_rent_t const rent = fd_sysvar_rent_read_nofail( borrowed_acct->instr_ctx->sysvar_cache ); + if( FD_UNLIKELY( acct->vt->get_lamports( acct ) < fd_rent_exempt_minimum_balance( &rent, acct->vt->get_data_len( acct ) ) ) ) { return FD_EXECUTOR_INSTR_ERR_EXECUTABLE_ACCOUNT_NOT_RENT_EXEMPT; } diff --git a/src/flamenco/runtime/fd_borrowed_account.h b/src/flamenco/runtime/fd_borrowed_account.h index 6bff3d6d12..1851391c43 100644 --- a/src/flamenco/runtime/fd_borrowed_account.h +++ b/src/flamenco/runtime/fd_borrowed_account.h @@ -4,7 +4,7 @@ #include "fd_executor_err.h" #include "fd_system_ids.h" #include "fd_runtime.h" -#include "context/fd_exec_txn_ctx.h" +#include "sysvar/fd_sysvar_cache.h" #include "sysvar/fd_sysvar_rent.h" /* FD_ACC_SZ_MAX is the hardcoded size limit of a Solana account. */ @@ -271,8 +271,8 @@ fd_borrowed_account_is_rent_exempt_at_data_length( fd_borrowed_account_t const * /* TODO: Add an is_exempt rent API to better match Agave and clean up code https://github.com/anza-xyz/agave/blob/v2.1.14/sdk/src/transaction_context.rs#L990 */ - fd_rent_t const * rent = fd_bank_rent_query( borrowed_acct->instr_ctx->txn_ctx->bank ); - ulong min_balance = fd_rent_exempt_minimum_balance( rent, acct->vt->get_data_len( acct ) ); + fd_rent_t rent = fd_sysvar_rent_read_nofail( borrowed_acct->instr_ctx->sysvar_cache ); + ulong min_balance = fd_rent_exempt_minimum_balance( &rent, acct->vt->get_data_len( acct ) ); return acct->vt->get_lamports( acct ) >= min_balance; } diff --git a/src/flamenco/runtime/fd_cost_tracker.c b/src/flamenco/runtime/fd_cost_tracker.c index 8093882d50..956d1d03a6 100644 --- a/src/flamenco/runtime/fd_cost_tracker.c +++ b/src/flamenco/runtime/fd_cost_tracker.c @@ -1,4 +1,6 @@ #include "fd_cost_tracker.h" +#include "context/fd_exec_slot_ctx.h" +#include "sysvar/fd_sysvar_recent_hashes.h" /* https://github.com/anza-xyz/agave/blob/v2.2.0/cost-model/src/cost_model.rs#L323-L328 */ FD_FN_PURE static inline ulong diff --git a/src/flamenco/runtime/fd_executor.c b/src/flamenco/runtime/fd_executor.c index 8154d9be9b..f82bb7b451 100644 --- a/src/flamenco/runtime/fd_executor.c +++ b/src/flamenco/runtime/fd_executor.c @@ -4,9 +4,7 @@ #include "fd_runtime.h" #include "fd_runtime_err.h" -#include "context/fd_exec_slot_ctx.h" #include "context/fd_exec_txn_ctx.h" -#include "context/fd_exec_instr_ctx.h" #include "../../util/rng/fd_rng.h" #include "fd_system_ids.h" @@ -306,33 +304,6 @@ fd_validate_fee_payer( fd_txn_account_t * account, return fd_executor_check_rent_state_with_account( account, &payer_pre_rent_state, &payer_post_rent_state ); } -static int FD_FN_UNUSED -status_check_tower( ulong slot, void * _ctx ) { - fd_exec_txn_ctx_t * ctx = (fd_exec_txn_ctx_t *)_ctx; - if( slot==ctx->slot ) { - return 1; - } - - if( fd_txncache_is_rooted_slot( ctx->status_cache, slot ) ) { - return 1; - } - - fd_slot_history_global_t * slot_history = fd_sysvar_slot_history_read( ctx->funk, - ctx->funk_txn, - ctx->spad ); - if( FD_UNLIKELY( !slot_history ) ) { - FD_LOG_ERR(( "Unable to read and decode slot history sysvar" )); - } - - if( fd_sysvar_slot_history_find_slot( slot_history, - slot, - ctx->runtime_pub_wksp ) == FD_SLOT_HISTORY_SLOT_FOUND ) { - return 1; - } - - return 0; -} - static int fd_executor_check_status_cache( fd_exec_txn_ctx_t * txn_ctx ) { @@ -457,11 +428,12 @@ load_transaction_account( fd_exec_txn_ctx_t * txn_ctx, https://github.com/anza-xyz/agave/blob/v2.2.0/svm/src/account_loader.rs#L552-L565 */ if( FD_LIKELY( !unknown_acc ) ) { if( is_writable ) { - txn_ctx->collected_rent += fd_runtime_collect_rent_from_account( fd_bank_epoch_schedule_query( txn_ctx->bank ), - fd_bank_rent_query( txn_ctx->bank ), - fd_bank_slots_per_year_get( txn_ctx->bank ), - acct, - epoch ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( txn_ctx->sysvar_cache ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail ( txn_ctx->sysvar_cache ); + txn_ctx->collected_rent += fd_runtime_collect_rent_from_account( + &epoch_schedule, &rent, + fd_bank_slots_per_year_get( txn_ctx->bank ), + acct, epoch ); acct->starting_lamports = acct->vt->get_lamports( acct ); /* TODO: why do we do this everywhere? */ } return; @@ -483,13 +455,10 @@ load_transaction_account( fd_exec_txn_ctx_t * txn_ctx, https://github.com/anza-xyz/agave/blob/v2.2.0/svm/src/account_loader.rs#L393-L534 */ int fd_executor_load_transaction_accounts( fd_exec_txn_ctx_t * txn_ctx ) { - ulong requested_loaded_accounts_data_size = txn_ctx->loaded_accounts_data_size_limit; - fd_epoch_schedule_t const * schedule = fd_sysvar_epoch_schedule_read( txn_ctx->funk, txn_ctx->funk_txn, txn_ctx->spad ); - if( FD_UNLIKELY( !schedule ) ) { - FD_LOG_ERR(( "Unable to read and decode epoch schedule sysvar" )); - } + ulong requested_loaded_accounts_data_size = txn_ctx->loaded_accounts_data_size_limit; - ulong epoch = fd_slot_to_epoch( schedule, txn_ctx->slot, NULL ); + fd_epoch_schedule_t const schedule = fd_sysvar_epoch_schedule_read_nofail( txn_ctx->sysvar_cache ); + ulong epoch = fd_slot_to_epoch( &schedule, txn_ctx->slot, NULL ); /* https://github.com/anza-xyz/agave/blob/v2.2.0/svm/src/account_loader.rs#L429-L443 */ for( ushort i=0; iaccounts_cnt; i++ ) { @@ -824,14 +793,16 @@ fd_executor_validate_transaction_fee_payer( fd_exec_txn_ctx_t * txn_ctx ) { return FD_RUNTIME_TXN_ERR_ACCOUNT_NOT_FOUND; } + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( txn_ctx->sysvar_cache ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail ( txn_ctx->sysvar_cache ); + /* Collect rent from the fee payer https://github.com/anza-xyz/agave/blob/v2.2.13/svm/src/transaction_processor.rs#L583-L589 */ - ulong epoch = fd_slot_to_epoch( fd_bank_epoch_schedule_query( txn_ctx->bank ), txn_ctx->slot, NULL ); - txn_ctx->collected_rent += fd_runtime_collect_rent_from_account( fd_bank_epoch_schedule_query( txn_ctx->bank ), - fd_bank_rent_query( txn_ctx->bank ), - fd_bank_slots_per_year_get( txn_ctx->bank ), - fee_payer_rec, - epoch ); + txn_ctx->collected_rent += fd_runtime_collect_rent_from_account( + &epoch_schedule, &rent, + fd_bank_slots_per_year_get( txn_ctx->bank ), + fee_payer_rec, + fd_slot_to_epoch( &epoch_schedule, txn_ctx->slot, NULL ) ); /* Calculate transaction fees https://github.com/anza-xyz/agave/blob/v2.2.13/svm/src/transaction_processor.rs#L597-L606 */ @@ -846,7 +817,7 @@ fd_executor_validate_transaction_fee_payer( fd_exec_txn_ctx_t * txn_ctx ) { } /* https://github.com/anza-xyz/agave/blob/v2.2.13/svm/src/transaction_processor.rs#L609-L616 */ - err = fd_validate_fee_payer( fee_payer_rec, fd_bank_rent_query( txn_ctx->bank ), total_fee, txn_ctx->spad ); + err = fd_validate_fee_payer( fee_payer_rec, &rent, total_fee, txn_ctx->spad ); if( FD_UNLIKELY( err ) ) { return err; } @@ -883,21 +854,20 @@ int fd_executor_setup_txn_alut_account_keys( fd_exec_txn_ctx_t * txn_ctx ) { if( txn_ctx->txn_descriptor->transaction_version == FD_TXN_V0 ) { /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/runtime/src/bank/address_lookup_table.rs#L44-L48 */ - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( txn_ctx->funk, txn_ctx->funk_txn, txn_ctx->spad ); - if( FD_UNLIKELY( !slot_hashes_global ) ) { + fd_slot_hash_t const * slot_hashes = fd_sysvar_slot_hashes_join_const( txn_ctx->sysvar_cache ); + if( FD_UNLIKELY( !slot_hashes ) ) { return FD_RUNTIME_TXN_ERR_ACCOUNT_NOT_FOUND; } - fd_slot_hash_t * slot_hash = deq_fd_slot_hash_t_join( (uchar *)slot_hashes_global + slot_hashes_global->hashes_offset ); - fd_acct_addr_t * accts_alt = (fd_acct_addr_t *) fd_type_pun( &txn_ctx->account_keys[txn_ctx->accounts_cnt] ); int err = fd_runtime_load_txn_address_lookup_tables( txn_ctx->txn_descriptor, txn_ctx->_txn_raw->raw, txn_ctx->funk, txn_ctx->funk_txn, txn_ctx->slot, - slot_hash, + slot_hashes, accts_alt ); + fd_sysvar_slot_hashes_leave_const( txn_ctx->sysvar_cache, slot_hashes ); txn_ctx->accounts_cnt += txn_ctx->txn_descriptor->addr_table_adtl_cnt; if( FD_UNLIKELY( err!=FD_RUNTIME_EXECUTE_SUCCESS ) ) return err; @@ -1208,25 +1178,6 @@ fd_txn_reclaim_accounts( fd_exec_txn_ctx_t * txn_ctx ) { } } -int -fd_executor_is_blockhash_valid_for_age( fd_block_hash_queue_global_t const * block_hash_queue, - fd_hash_t const * blockhash, - ulong max_age ) { - fd_hash_hash_age_pair_t_mapnode_t key; - fd_memcpy( key.elem.key.uc, blockhash, sizeof(fd_hash_t) ); - - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_block_hash_queue_ages_pool_join( block_hash_queue ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = fd_block_hash_queue_ages_root_join( block_hash_queue ); - - fd_hash_hash_age_pair_t_mapnode_t * hash_age = fd_hash_hash_age_pair_t_map_find( ages_pool, ages_root, &key ); - if( hash_age==NULL ) { - return 0; - } - - ulong age = block_hash_queue->last_hash_index-hash_age->elem.val.hash_index; - return age<=max_age; -} - void fd_exec_txn_ctx_from_exec_slot_ctx( fd_exec_slot_ctx_t const * slot_ctx, fd_exec_txn_ctx_t * ctx, @@ -1461,7 +1412,7 @@ fd_execute_txn( fd_execute_txn_task_info_t * task_info ) { int fd_executor_txn_check( fd_exec_txn_ctx_t * txn_ctx ) { - fd_rent_t const * rent = fd_bank_rent_query( txn_ctx->bank ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail( txn_ctx->sysvar_cache ); ulong starting_lamports_l = 0; ulong starting_lamports_h = 0; @@ -1486,7 +1437,7 @@ fd_executor_txn_check( fd_exec_txn_ctx_t * txn_ctx ) { - lamports >= rent_exempt_minimum -> RentExempt In Agave, 'self' refers to our 'after' state. */ uchar after_uninitialized = b->vt->get_lamports( b ) == 0; - uchar after_rent_exempt = b->vt->get_lamports( b ) >= fd_rent_exempt_minimum_balance( rent, b->vt->get_data_len( b ) ); + uchar after_rent_exempt = b->vt->get_lamports( b ) >= fd_rent_exempt_minimum_balance( &rent, b->vt->get_data_len( b ) ); /* https://github.com/anza-xyz/agave/blob/b2c388d6cbff9b765d574bbb83a4378a1fc8af32/svm/src/account_rent_state.rs#L96 */ if( FD_LIKELY( memcmp( b->pubkey->key, fd_sysvar_incinerator_id.key, sizeof(fd_pubkey_t) ) != 0 ) ) { @@ -1496,7 +1447,7 @@ fd_executor_txn_check( fd_exec_txn_ctx_t * txn_ctx ) { } else { /* https://github.com/anza-xyz/agave/blob/b2c388d6cbff9b765d574bbb83a4378a1fc8af32/svm/src/account_rent_state.rs#L45-L59 */ uchar before_uninitialized = b->starting_dlen == ULONG_MAX || b->starting_lamports == 0; - uchar before_rent_exempt = b->starting_dlen != ULONG_MAX && b->starting_lamports >= fd_rent_exempt_minimum_balance( rent, b->starting_dlen ); + uchar before_rent_exempt = b->starting_dlen != ULONG_MAX && b->starting_lamports >= fd_rent_exempt_minimum_balance( &rent, b->starting_dlen ); /* https://github.com/anza-xyz/agave/blob/b2c388d6cbff9b765d574bbb83a4378a1fc8af32/svm/src/account_rent_state.rs#L50 */ if( before_uninitialized || before_rent_exempt ) { @@ -1506,8 +1457,8 @@ fd_executor_txn_check( fd_exec_txn_ctx_t * txn_ctx ) { b->starting_dlen, b->vt->get_lamports( b ), b->starting_lamports, - fd_rent_exempt_minimum_balance( rent, b->vt->get_data_len( b ) ), - fd_rent_exempt_minimum_balance( rent, b->starting_dlen ) )); + fd_rent_exempt_minimum_balance( &rent, b->vt->get_data_len( b ) ), + fd_rent_exempt_minimum_balance( &rent, b->starting_dlen ) )); /* https://github.com/anza-xyz/agave/blob/b2c388d6cbff9b765d574bbb83a4378a1fc8af32/svm/src/account_rent_state.rs#L104 */ return FD_RUNTIME_TXN_ERR_INSUFFICIENT_FUNDS_FOR_RENT; /* https://github.com/anza-xyz/agave/blob/b2c388d6cbff9b765d574bbb83a4378a1fc8af32/svm/src/account_rent_state.rs#L56 */ @@ -1520,8 +1471,8 @@ fd_executor_txn_check( fd_exec_txn_ctx_t * txn_ctx ) { b->starting_dlen, b->vt->get_lamports( b ), b->starting_lamports, - fd_rent_exempt_minimum_balance( rent, b->vt->get_data_len( b ) ), - fd_rent_exempt_minimum_balance( rent, b->starting_dlen ) )); + fd_rent_exempt_minimum_balance( &rent, b->vt->get_data_len( b ) ), + fd_rent_exempt_minimum_balance( &rent, b->starting_dlen ) )); /* https://github.com/anza-xyz/agave/blob/b2c388d6cbff9b765d574bbb83a4378a1fc8af32/svm/src/account_rent_state.rs#L104 */ return FD_RUNTIME_TXN_ERR_INSUFFICIENT_FUNDS_FOR_RENT; } diff --git a/src/flamenco/runtime/fd_executor.h b/src/flamenco/runtime/fd_executor.h index 25acca6292..feea7b411d 100644 --- a/src/flamenco/runtime/fd_executor.h +++ b/src/flamenco/runtime/fd_executor.h @@ -104,11 +104,6 @@ fd_executor_txn_check( fd_exec_txn_ctx_t * txn_ctx ); void fd_txn_reclaim_accounts( fd_exec_txn_ctx_t * txn_ctx ); -int -fd_executor_is_blockhash_valid_for_age( fd_block_hash_queue_global_t const * block_hash_queue, - fd_hash_t const * blockhash, - ulong max_age ); - /* fd_io_strerror converts an FD_EXECUTOR_INSTR_ERR_{...} code into a human readable cstr. The lifetime of the returned pointer is infinite and the call itself is thread safe. The returned pointer is diff --git a/src/flamenco/runtime/fd_hashes.c b/src/flamenco/runtime/fd_hashes.c index 69b9b5f04c..f6b8b5a0cd 100644 --- a/src/flamenco/runtime/fd_hashes.c +++ b/src/flamenco/runtime/fd_hashes.c @@ -139,20 +139,20 @@ fd_hash_account_deltas( fd_pubkey_hash_pair_list_t * lists, ulong lists_len, fd_ void -fd_calculate_epoch_accounts_hash_values( fd_exec_slot_ctx_t * slot_ctx ) { - ulong slot_idx = 0; - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), &slot_idx ); +fd_calculate_epoch_accounts_hash_values( fd_bank_t * bank ) { + ulong epoch = fd_bank_epoch_get( bank ); - if( FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, accounts_lt_hash) ) { - fd_bank_eah_start_slot_set( slot_ctx->bank, ULONG_MAX ); - fd_bank_eah_stop_slot_set( slot_ctx->bank, ULONG_MAX ); - fd_bank_eah_interval_set( slot_ctx->bank, ULONG_MAX ); + if( FD_FEATURE_ACTIVE_BANK( bank, accounts_lt_hash) ) { + fd_bank_eah_start_slot_set( bank, ULONG_MAX ); + fd_bank_eah_stop_slot_set( bank, ULONG_MAX ); + fd_bank_eah_interval_set( bank, ULONG_MAX ); return; } - ulong slots_per_epoch = fd_epoch_slot_cnt( epoch_schedule, epoch ); - ulong first_slot_in_epoch = fd_epoch_slot0 ( epoch_schedule, epoch ); + fd_epoch_schedule_t epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( bank ) ); + ulong slots_per_epoch = fd_epoch_slot_cnt( &epoch_schedule, epoch ); + ulong first_slot_in_epoch = fd_epoch_slot0 ( &epoch_schedule, epoch ); ulong calculation_offset_start = slots_per_epoch / 4; ulong calculation_offset_stop = slots_per_epoch / 4 * 3; @@ -164,23 +164,23 @@ fd_calculate_epoch_accounts_hash_values( fd_exec_slot_ctx_t * slot_ctx ) { const ulong MINIMUM_CALCULATION_INTERVAL = MAX_LOCKOUT_HISTORY + CALCULATION_INTERVAL_BUFFER; if( calculation_interval < MINIMUM_CALCULATION_INTERVAL ) { - fd_bank_eah_start_slot_set( slot_ctx->bank, ULONG_MAX ); - fd_bank_eah_stop_slot_set( slot_ctx->bank, ULONG_MAX ); - fd_bank_eah_interval_set( slot_ctx->bank, ULONG_MAX ); + fd_bank_eah_start_slot_set( bank, ULONG_MAX ); + fd_bank_eah_stop_slot_set( bank, ULONG_MAX ); + fd_bank_eah_interval_set( bank, ULONG_MAX ); return; } - fd_bank_eah_start_slot_set( slot_ctx->bank, first_slot_in_epoch + calculation_offset_start ); - if( fd_bank_slot_get( slot_ctx->bank ) > fd_bank_eah_start_slot_get( slot_ctx->bank ) ) { - fd_bank_eah_start_slot_set( slot_ctx->bank, ULONG_MAX ); + fd_bank_eah_start_slot_set( bank, first_slot_in_epoch + calculation_offset_start ); + if( fd_bank_slot_get( bank ) > fd_bank_eah_start_slot_get( bank ) ) { + fd_bank_eah_start_slot_set( bank, ULONG_MAX ); } - fd_bank_eah_stop_slot_set( slot_ctx->bank, first_slot_in_epoch + calculation_offset_stop ); - if( fd_bank_slot_get( slot_ctx->bank ) > fd_bank_eah_stop_slot_get( slot_ctx->bank ) ) { - fd_bank_eah_stop_slot_set( slot_ctx->bank, ULONG_MAX ); + fd_bank_eah_stop_slot_set( bank, first_slot_in_epoch + calculation_offset_stop ); + if( fd_bank_slot_get( bank ) > fd_bank_eah_stop_slot_get( bank ) ) { + fd_bank_eah_stop_slot_set( bank, ULONG_MAX ); } - fd_bank_eah_interval_set( slot_ctx->bank, calculation_interval ); + fd_bank_eah_interval_set( bank, calculation_interval ); } diff --git a/src/flamenco/runtime/fd_hashes.h b/src/flamenco/runtime/fd_hashes.h index 1519ae4388..8493f3508c 100644 --- a/src/flamenco/runtime/fd_hashes.h +++ b/src/flamenco/runtime/fd_hashes.h @@ -192,7 +192,7 @@ fd_accounts_check_lthash( fd_funk_t * funk, fd_features_t * features ); void -fd_calculate_epoch_accounts_hash_values(fd_exec_slot_ctx_t * slot_ctx); +fd_calculate_epoch_accounts_hash_values( fd_bank_t * bank ); int fd_accounts_hash_inc_only( fd_exec_slot_ctx_t * slot_ctx, diff --git a/src/flamenco/runtime/fd_runtime.c b/src/flamenco/runtime/fd_runtime.c index df372d4add..542cddd39c 100644 --- a/src/flamenco/runtime/fd_runtime.c +++ b/src/flamenco/runtime/fd_runtime.c @@ -2,6 +2,7 @@ #include "context/fd_capture_ctx.h" #include "fd_acc_mgr.h" #include "fd_bank.h" +#include "fd_blockhashes.h" #include "fd_runtime_err.h" #include "fd_runtime_init.h" #include "fd_pubkey_utils.h" @@ -9,31 +10,24 @@ #include "fd_executor.h" #include "fd_cost_tracker.h" #include "fd_runtime_public.h" -#include "fd_txncache.h" +#include "sysvar/fd_sysvar_cache.h" #include "sysvar/fd_sysvar_clock.h" #include "sysvar/fd_sysvar_epoch_schedule.h" #include "sysvar/fd_sysvar_recent_hashes.h" #include "sysvar/fd_sysvar_stake_history.h" -#include "sysvar/fd_sysvar.h" -#include "../../ballet/base58/fd_base58.h" -#include "../../ballet/txn/fd_txn.h" -#include "../../ballet/bmtree/fd_bmtree.h" #include "../stakes/fd_stakes.h" #include "../rewards/fd_rewards.h" #include "context/fd_exec_txn_ctx.h" -#include "context/fd_exec_instr_ctx.h" #include "info/fd_microblock_batch_info.h" #include "info/fd_microblock_info.h" #include "program/fd_stake_program.h" #include "program/fd_builtin_programs.h" -#include "program/fd_system_program.h" #include "program/fd_vote_program.h" #include "program/fd_bpf_program_util.h" #include "program/fd_bpf_loader_program.h" -#include "program/fd_compute_budget_program.h" #include "program/fd_address_lookup_table_program.h" #include "sysvar/fd_sysvar_clock.h" @@ -45,18 +39,10 @@ #include "tests/fd_dump_pb.h" -#include "../../ballet/nanopb/pb_decode.h" -#include "../../ballet/nanopb/pb_encode.h" -#include "../types/fd_solana_block.pb.h" - #include "fd_system_ids.h" -#include "../vm/fd_vm.h" #include "fd_blockstore.h" #include "../../disco/pack/fd_pack.h" -#include "../fd_rwlock.h" -#include -#include #include #include #include @@ -105,29 +91,31 @@ fd_runtime_update_slots_per_epoch( fd_bank_t * bank, } void -fd_runtime_update_leaders( fd_bank_t * bank, - ulong slot, - fd_spad_t * runtime_spad ) { +fd_runtime_update_leaders( fd_exec_slot_ctx_t * slot_ctx, + ulong slot, + fd_spad_t * runtime_spad ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { + fd_bank_t * bank = slot_ctx->bank; + fd_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( bank ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( sysvar_cache ); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( bank ); + FD_SPAD_FRAME_BEGIN( runtime_spad ) { - FD_LOG_INFO(( "schedule->slots_per_epoch = %lu", epoch_schedule->slots_per_epoch )); - FD_LOG_INFO(( "schedule->leader_schedule_slot_offset = %lu", epoch_schedule->leader_schedule_slot_offset )); - FD_LOG_INFO(( "schedule->warmup = %d", epoch_schedule->warmup )); - FD_LOG_INFO(( "schedule->first_normal_epoch = %lu", epoch_schedule->first_normal_epoch )); - FD_LOG_INFO(( "schedule->first_normal_slot = %lu", epoch_schedule->first_normal_slot )); + FD_LOG_INFO(( "schedule->slots_per_epoch = %lu", epoch_schedule.slots_per_epoch )); + FD_LOG_INFO(( "schedule->leader_schedule_slot_offset = %lu", epoch_schedule.leader_schedule_slot_offset )); + FD_LOG_INFO(( "schedule->warmup = %d", epoch_schedule.warmup )); + FD_LOG_INFO(( "schedule->first_normal_epoch = %lu", epoch_schedule.first_normal_epoch )); + FD_LOG_INFO(( "schedule->first_normal_slot = %lu", epoch_schedule.first_normal_slot )); fd_vote_accounts_global_t const * epoch_vaccs = fd_bank_epoch_stakes_locking_query( bank ); fd_vote_accounts_pair_global_t_mapnode_t * vote_acc_pool = fd_vote_accounts_vote_accounts_pool_join( epoch_vaccs ); fd_vote_accounts_pair_global_t_mapnode_t * vote_acc_root = fd_vote_accounts_vote_accounts_root_join( epoch_vaccs ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, slot, NULL ); - ulong slot0 = fd_epoch_slot0( epoch_schedule, epoch ); - ulong slot_cnt = fd_epoch_slot_cnt( epoch_schedule, epoch ); + ulong epoch = fd_slot_to_epoch( &epoch_schedule, slot, NULL ); + ulong slot0 = fd_epoch_slot0( &epoch_schedule, epoch ); + ulong slot_cnt = fd_epoch_slot_cnt( &epoch_schedule, epoch ); - fd_runtime_update_slots_per_epoch( bank, fd_epoch_slot_cnt( epoch_schedule, epoch ) ); + fd_runtime_update_slots_per_epoch( bank, fd_epoch_slot_cnt( &epoch_schedule, epoch ) ); ulong vote_acc_cnt = fd_vote_accounts_pair_global_t_map_size( vote_acc_pool, vote_acc_root ); fd_bank_epoch_stakes_end_locking_query( bank ); @@ -178,7 +166,7 @@ fd_runtime_update_leaders( fd_bank_t * bank, Returns 0 if validation succeeds Returns the amount to burn(==fee) on failure */ static ulong -fd_runtime_validate_fee_collector( fd_bank_t * bank, +fd_runtime_validate_fee_collector( fd_rent_t const * rent, fd_txn_account_t const * collector, ulong fee ) { if( FD_UNLIKELY( fee<=0UL ) ) { @@ -213,7 +201,6 @@ fd_runtime_validate_fee_collector( fd_bank_t * bank, We already know that the post deposit balance is >0 because we are paying a >0 amount. So TLDR we just check if the account is rent exempt. */ - fd_rent_t const * rent = fd_bank_rent_query( bank ); ulong minbal = fd_rent_exempt_minimum_balance( rent, collector->vt->get_data_len( collector ) ); if( FD_UNLIKELY( collector->vt->get_lamports( collector ) + fee < minbal ) ) { FD_BASE58_ENCODE_32_BYTES( collector->pubkey->key, _out_key ); @@ -251,9 +238,9 @@ fd_runtime_run_incinerator( fd_bank_t * bank, } static void -fd_runtime_freeze( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { +fd_runtime_freeze( fd_exec_slot_ctx_t * slot_ctx ) { - fd_sysvar_recent_hashes_update( slot_ctx, runtime_spad ); + fd_sysvar_recent_hashes_update( slot_ctx ); ulong execution_fees = fd_bank_execution_fees_get( slot_ctx->bank ); ulong priority_fees = fd_bank_priority_fees_get( slot_ctx->bank ); @@ -294,8 +281,11 @@ fd_runtime_freeze( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { fd_bank_epoch_leaders_end_locking_query( slot_ctx->bank ); if ( FD_LIKELY( FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, validate_fee_collector_account ) ) ) { + fd_rent_t const rent = + fd_sysvar_rent_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + ulong _burn; - if( FD_UNLIKELY( _burn=fd_runtime_validate_fee_collector( slot_ctx->bank, rec, fees ) ) ) { + if( FD_UNLIKELY( _burn=fd_runtime_validate_fee_collector( &rent, rec, fees ) ) ) { if( FD_UNLIKELY( _burn!=fees ) ) { FD_LOG_ERR(( "expected _burn(%lu)==fees(%lu)", _burn, fees )); } @@ -406,7 +396,7 @@ fd_runtime_collect_rent_from_account( fd_epoch_schedule_t const * schedule, */ static void fd_runtime_new_fee_rate_governor_derived( fd_bank_t * bank, - ulong latest_singatures_per_slot ) { + ulong latest_signatures_per_slot ) { fd_fee_rate_governor_t const * base_fee_rate_governor = fd_bank_fee_rate_governor_query( bank ); @@ -429,7 +419,7 @@ fd_runtime_new_fee_rate_governor_derived( fd_bank_t * bank, fd_ulong_max( me.min_lamports_per_signature, me.target_lamports_per_signature - * fd_ulong_min(latest_singatures_per_slot, (ulong)UINT_MAX) + * fd_ulong_min(latest_signatures_per_slot, (ulong)UINT_MAX) / me.target_signatures_per_slot ) ); @@ -477,16 +467,16 @@ fd_runtime_block_sysvar_update_pre_execute( fd_exec_slot_ctx_t * slot_ctx, // TODO: move all these out to a fd_sysvar_update() call... long clock_update_time = -fd_log_wallclock(); - fd_sysvar_clock_update( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); + fd_sysvar_clock_update( slot_ctx, runtime_spad ); clock_update_time += fd_log_wallclock(); double clock_update_time_ms = (double)clock_update_time * 1e-6; FD_LOG_INFO(( "clock updated - slot: %lu, elapsed: %6.6f ms", fd_bank_slot_get( slot_ctx->bank ), clock_update_time_ms )); // It has to go into the current txn previous info but is not in slot 0 if( fd_bank_slot_get( slot_ctx->bank ) != 0 ) { - fd_sysvar_slot_hashes_update( slot_ctx, runtime_spad ); + fd_sysvar_slot_hashes_update( slot_ctx ); } - fd_sysvar_last_restart_slot_update( slot_ctx, runtime_spad ); + fd_sysvar_last_restart_slot_update( slot_ctx, fd_bank_last_restart_slot_get( slot_ctx->bank ).slot ); return 0; } @@ -677,13 +667,15 @@ fd_runtime_block_verify_ticks( fd_blockstore_t * blockstore, } int -fd_runtime_load_txn_address_lookup_tables( fd_txn_t const * txn, - uchar const * payload, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - ulong slot, - fd_slot_hash_t * hashes, - fd_acct_addr_t * out_accts_alt ) { +fd_runtime_load_txn_address_lookup_tables( + fd_txn_t const * txn, + uchar const * payload, + fd_funk_t * funk, + fd_funk_txn_t * funk_txn, + ulong slot, + fd_slot_hash_t const * hashes, /* deque */ + fd_acct_addr_t * out_accts_alt +) { if( FD_LIKELY( txn->transaction_version!=FD_TXN_V0 ) ) return FD_RUNTIME_EXECUTE_SUCCESS; @@ -1014,7 +1006,7 @@ fd_runtime_block_execute_finalize_start( fd_exec_slot_ctx_t * slot_c fd_sysvar_slot_history_update( slot_ctx, runtime_spad ); /* This slot is now "frozen" and can't be changed anymore. */ - fd_runtime_freeze( slot_ctx, runtime_spad ); + fd_runtime_freeze( slot_ctx ); int result = fd_bpf_scan_and_create_bpf_program_cache_entry( slot_ctx, runtime_spad ); if( FD_UNLIKELY( result ) ) { @@ -1777,12 +1769,8 @@ fd_new_target_program_account( fd_exec_slot_ctx_t * slot_ctx, }; /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L89-L90 */ - fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank ); - if( FD_UNLIKELY( rent==NULL ) ) { - return -1; - } - - out_rec->vt->set_lamports( out_rec, fd_rent_exempt_minimum_balance( rent, SIZE_OF_PROGRAM ) ); + fd_rent_t rent = fd_sysvar_rent_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + out_rec->vt->set_lamports( out_rec, fd_rent_exempt_minimum_balance( &rent, SIZE_OF_PROGRAM ) ); fd_bincode_encode_ctx_t ctx = { .data = out_rec->vt->get_data_mut( out_rec ), .dataend = out_rec->vt->get_data_mut( out_rec ) + SIZE_OF_PROGRAM, @@ -1839,14 +1827,10 @@ fd_new_target_program_data_account( fd_exec_slot_ctx_t * slot_ctx, } /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L127-L132 */ - fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank ); - if( FD_UNLIKELY( rent==NULL ) ) { - return -1; - } - - const uchar * elf = buffer_acc_rec->vt->get_data( buffer_acc_rec ) + BUFFER_METADATA_SIZE; - ulong space = PROGRAMDATA_METADATA_SIZE - BUFFER_METADATA_SIZE + buffer_acc_rec->vt->get_data_len( buffer_acc_rec ); - ulong lamports = fd_rent_exempt_minimum_balance( rent, space ); + uchar const * elf = buffer_acc_rec->vt->get_data( buffer_acc_rec ) + BUFFER_METADATA_SIZE; + ulong space = PROGRAMDATA_METADATA_SIZE - BUFFER_METADATA_SIZE + buffer_acc_rec->vt->get_data_len( buffer_acc_rec ); + fd_rent_t rent = fd_sysvar_rent_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + ulong lamports = fd_rent_exempt_minimum_balance( &rent, space ); /* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank/builtins/core_bpf_migration/mod.rs#L134-L137 */ fd_bpf_upgradeable_loader_state_t programdata_metadata = { @@ -2217,11 +2201,13 @@ fd_features_activate( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) } uint -fd_runtime_is_epoch_boundary( fd_exec_slot_ctx_t * slot_ctx, ulong curr_slot, ulong prev_slot ) { +fd_runtime_is_epoch_boundary( fd_exec_slot_ctx_t * slot_ctx, + ulong curr_slot, + ulong prev_slot ) { ulong slot_idx; - fd_epoch_schedule_t const * schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong prev_epoch = fd_slot_to_epoch( schedule, prev_slot, &slot_idx ); - ulong new_epoch = fd_slot_to_epoch( schedule, curr_slot, &slot_idx ); + fd_epoch_schedule_t const schedule = fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + ulong prev_epoch = fd_slot_to_epoch( &schedule, prev_slot, &slot_idx ); + ulong new_epoch = fd_slot_to_epoch( &schedule, curr_slot, &slot_idx ); return ( prev_epoch < new_epoch || slot_idx == 0 ); } @@ -2252,9 +2238,9 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, long start = fd_log_wallclock(); - ulong slot; - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), &slot ); + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + ulong const slot = fd_bank_slot_get ( slot_ctx->bank ); + ulong const epoch = fd_bank_epoch_get( slot_ctx->bank ); /* Activate new features https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/bank.rs#L6587-L6598 */ @@ -2269,13 +2255,12 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, int _err[1]; ulong new_rate_activation_epoch_val = 0UL; ulong * new_rate_activation_epoch = &new_rate_activation_epoch_val; - int is_some = fd_new_warmup_cooldown_rate_epoch( fd_bank_slot_get( slot_ctx->bank ), - slot_ctx->funk, - slot_ctx->funk_txn, - runtime_spad, - fd_bank_features_query( slot_ctx->bank ), - new_rate_activation_epoch, - _err ); + int is_some = fd_new_warmup_cooldown_rate_epoch( + sysvar_cache, + fd_bank_features_query( slot_ctx->bank ), + slot, + new_rate_activation_epoch, + _err ); if( FD_UNLIKELY( !is_some ) ) { new_rate_activation_epoch = NULL; } @@ -2309,7 +2294,7 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, /* Refresh vote accounts in stakes cache using updated stake weights, and merges slot bank vote accounts with the epoch bank vote accounts. https://github.com/anza-xyz/agave/blob/v2.1.6/runtime/src/stakes.rs#L363-L370 */ - fd_stake_history_t const * history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); + fd_stake_history_t const * history = fd_sysvar_stake_history_join( sysvar_cache ); if( FD_UNLIKELY( !history ) ) { FD_LOG_ERR(( "StakeHistory sysvar could not be read and decoded" )); } @@ -2335,11 +2320,16 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, /* Distribute rewards */ - fd_block_hash_queue_global_t const * bhq = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0]; - fd_hash_t const * parent_blockhash = fd_block_hash_queue_last_hash_join( bhq ); + fd_hash_t parent_blockhash = {0}; + { + fd_blockhashes_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank ); + fd_hash_t const * bhq_last = fd_blockhashes_peek_last( bhq ); + FD_TEST( bhq_last ); + parent_blockhash = *bhq_last; + } fd_begin_partitioned_rewards( slot_ctx, - parent_blockhash, + &parent_blockhash, parent_epoch, &temp_info, tpool, @@ -2353,10 +2343,10 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, /* Replace stakes at T-1 (next_epoch_stakes) by updated stakes at T (stakes->vote_accounts) */ fd_update_next_epoch_stakes( slot_ctx ); - /* Update current leaders using epoch_stakes (new T-2 stakes) */ - fd_runtime_update_leaders( slot_ctx->bank, fd_bank_slot_get( slot_ctx->bank ), runtime_spad ); + /* Update current leaders using slot_ctx->slot_bank.epoch_stakes (new T-2 stakes) */ + fd_runtime_update_leaders( slot_ctx, fd_bank_slot_get( slot_ctx->bank ), runtime_spad ); - fd_calculate_epoch_accounts_hash_values( slot_ctx ); + fd_calculate_epoch_accounts_hash_values( slot_ctx->bank ); FD_LOG_NOTICE(( "fd_process_new_epoch end" )); @@ -2403,20 +2393,17 @@ fd_runtime_update_program_cache( fd_exec_slot_ctx_t * slot_ctx, /* Iterate over account keys referenced in ALUTs */ fd_acct_addr_t alut_accounts[256]; - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); - if( FD_UNLIKELY( !slot_hashes_global ) ) { - return; - } - - fd_slot_hash_t * slot_hash = deq_fd_slot_hash_t_join( (uchar *)slot_hashes_global + slot_hashes_global->hashes_offset ); - - if( FD_UNLIKELY( fd_runtime_load_txn_address_lookup_tables( txn_descriptor, - txn_p->payload, - slot_ctx->funk, - slot_ctx->funk_txn, - fd_bank_slot_get( slot_ctx->bank ), - slot_hash, - alut_accounts ) ) ) { + fd_slot_hash_t const * slot_hash = fd_sysvar_slot_hashes_join_const( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); + if( FD_UNLIKELY( !slot_hash ) ) return; /* FIXME is this valid behavior? */ + + if( FD_UNLIKELY( fd_runtime_load_txn_address_lookup_tables( + txn_descriptor, + txn_p->payload, + slot_ctx->funk, + slot_ctx->funk_txn, + fd_bank_slot_get( slot_ctx->bank ), + slot_hash, + alut_accounts ) ) ) { return; } @@ -2828,11 +2815,10 @@ fd_runtime_block_collect_txns( fd_runtime_block_info_t const * block_info, static void fd_runtime_init_program( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { - fd_sysvar_recent_hashes_init( slot_ctx, runtime_spad ); - fd_sysvar_clock_init( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn ); + fd_sysvar_recent_hashes_init( slot_ctx ); + fd_sysvar_clock_init( slot_ctx ); fd_sysvar_slot_history_init( slot_ctx, runtime_spad ); - fd_sysvar_slot_hashes_init( slot_ctx, runtime_spad ); - fd_sysvar_epoch_schedule_init( slot_ctx ); + fd_sysvar_slot_hashes_init( slot_ctx ); fd_sysvar_rent_init( slot_ctx ); fd_sysvar_stake_history_init( slot_ctx ); fd_sysvar_last_restart_slot_init( slot_ctx ); @@ -2855,33 +2841,22 @@ fd_runtime_init_bank_from_genesis( fd_exec_slot_ctx_t * slot_ctx, fd_poh_config_t const * poh = &genesis_block->poh_config; uint128 target_tick_duration = ((uint128)poh->target_tick_duration.seconds * 1000000000UL + (uint128)poh->target_tick_duration.nanoseconds); - fd_bank_epoch_schedule_set( slot_ctx->bank, genesis_block->epoch_schedule ); + fd_sysvar_epoch_schedule_write( slot_ctx, &genesis_block->epoch_schedule ); - fd_bank_rent_set( slot_ctx->bank, genesis_block->rent ); + fd_sysvar_rent_write( slot_ctx, &genesis_block->rent ); fd_bank_block_height_set( slot_ctx->bank, 0UL ); fd_bank_inflation_set( slot_ctx->bank, genesis_block->inflation ); - fd_block_hash_queue_global_t * block_hash_queue = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0]; - uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)block_hash_queue + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) ); - uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 400 ) ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = NULL; - - fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( ages_pool ); - node->elem = (fd_hash_hash_age_pair_t){ - .key = *genesis_hash, - .val = (fd_hash_age_t){ .hash_index = 0UL, .fee_calculator = (fd_fee_calculator_t){ .lamports_per_signature = 0UL }, .timestamp = (ulong)fd_log_wallclock() } - }; - fd_hash_hash_age_pair_t_map_insert( ages_pool, &ages_root, node ); - fd_memcpy( last_hash_mem, genesis_hash, FD_HASH_FOOTPRINT ); - - block_hash_queue->last_hash_index = 0UL; - block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue; - block_hash_queue->ages_pool_offset = (ulong)fd_hash_hash_age_pair_t_map_leave( ages_pool ) - (ulong)block_hash_queue; - block_hash_queue->ages_root_offset = (ulong)ages_root - (ulong)block_hash_queue; - block_hash_queue->max_age = FD_BLOCKHASH_QUEUE_MAX_ENTRIES; + { + /* FIXME Why is there a previous blockhash at genesis? Why is the + last_hash field an option type in Agave, if even the first + real block has a previous blockhash? */ + fd_blockhashes_t * bhq = fd_bank_block_hash_queue_modify( slot_ctx->bank ); + fd_blockhash_info_t * info = fd_blockhashes_push( bhq, genesis_hash ); + info->fee_calculator.lamports_per_signature = 0UL; + } fd_bank_fee_rate_governor_set( slot_ctx->bank, genesis_block->fee_rate_governor ); @@ -3147,9 +3122,9 @@ fd_runtime_process_genesis_block( fd_exec_slot_ctx_t * slot_ctx, fd_sysvar_slot_history_update( slot_ctx, runtime_spad ); - fd_runtime_update_leaders( slot_ctx->bank, 0, runtime_spad ); + fd_runtime_update_leaders( slot_ctx, 0, runtime_spad ); - fd_runtime_freeze( slot_ctx, runtime_spad ); + fd_runtime_freeze( slot_ctx ); /* sort and update bank hash */ fd_hash_t * bank_hash = fd_bank_bank_hash_modify( slot_ctx->bank ); @@ -3654,12 +3629,14 @@ fd_runtime_block_pre_execute_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, /* Update block height. */ fd_bank_block_height_set( slot_ctx->bank, fd_bank_block_height_get( slot_ctx->bank ) + 1UL ); - if( fd_bank_slot_get( slot_ctx->bank ) != 0UL ) { - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); + ulong const slot = fd_bank_slot_get( slot_ctx->bank ); + if( slot != 0UL ) { + fd_epoch_schedule_t const epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( slot_ctx->bank ) ); - ulong slot_idx; - ulong prev_epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_parent_slot_get( slot_ctx->bank ), &slot_idx ); - ulong new_epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), &slot_idx ); + ulong prev_epoch = fd_slot_to_epoch( &epoch_schedule, fd_bank_parent_slot_get( slot_ctx->bank ), NULL ); + ulong slot_idx; + ulong new_epoch = fd_slot_to_epoch( &epoch_schedule, slot, &slot_idx ); if( FD_UNLIKELY( slot_idx==1UL && new_epoch==0UL ) ) { /* The block after genesis has a height of 1. */ fd_bank_block_height_set( slot_ctx->bank, 1UL ); @@ -3680,12 +3657,8 @@ fd_runtime_block_pre_execute_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, *is_epoch_boundary = 0; } - if( FD_LIKELY( fd_bank_slot_get( slot_ctx->bank )!=0UL ) ) { - fd_distribute_partitioned_epoch_rewards( slot_ctx, - tpool, - exec_spads, - exec_spad_cnt, - runtime_spad ); + if( FD_LIKELY( slot!=0UL ) ) { + fd_distribute_partitioned_epoch_rewards( slot_ctx ); } } diff --git a/src/flamenco/runtime/fd_runtime.h b/src/flamenco/runtime/fd_runtime.h index abdc8e7b7f..848634b84d 100644 --- a/src/flamenco/runtime/fd_runtime.h +++ b/src/flamenco/runtime/fd_runtime.h @@ -3,17 +3,11 @@ #include "stdarg.h" -#include "../fd_flamenco_base.h" -#include "fd_runtime_err.h" -#include "fd_runtime_init.h" #include "fd_rocksdb.h" #include "fd_acc_mgr.h" #include "fd_hashes.h" #include "../features/fd_features.h" #include "fd_rent_lists.h" -#include "../../ballet/poh/fd_poh.h" -#include "../leaders/fd_leaders.h" -#include "context/fd_exec_slot_ctx.h" #include "context/fd_capture_ctx.h" #include "context/fd_exec_txn_ctx.h" #include "info/fd_runtime_block_info.h" @@ -43,8 +37,7 @@ #define FD_RUNTIME_OFFLINE_NUM_ROOT_BLOCKS (6UL) /* 6 root blocks for offline replay */ -#define FD_BLOCKHASH_QUEUE_MAX_ENTRIES (300UL) -#define FD_RECENT_BLOCKHASHES_MAX_ENTRIES (150UL) +#define FD_BLOCKHASH_QUEUE_MAX_ENTRIES (300UL) #define FD_RENT_EXEMPT_RENT_EPOCH (ULONG_MAX) @@ -312,9 +305,9 @@ fd_runtime_compute_max_tick_height( ulong ticks_per_slot, ulong * out_max_tick_height /* out */ ); void -fd_runtime_update_leaders( fd_bank_t * bank, - ulong slot, - fd_spad_t * runtime_spad ); +fd_runtime_update_leaders( fd_exec_slot_ctx_t * slot_ctx, + ulong slot, + fd_spad_t * runtime_spad ); /* TODO: Invoked by fd_executor: layering violation. Rent logic is deprecated and will be torn out entirely very soon. */ @@ -483,7 +476,7 @@ fd_runtime_load_txn_address_lookup_tables( fd_txn_t const * txn, fd_funk_t * funk, fd_funk_txn_t * funk_txn, ulong slot, - fd_slot_hash_t * hashes, + fd_slot_hash_t const * hashes, fd_acct_addr_t * out_accts_alt ); /* fd_runtime_poh_verify is responsible for verifying poh hashes while diff --git a/src/flamenco/runtime/fd_runtime_init.c b/src/flamenco/runtime/fd_runtime_init.c index d3e30662d5..6fd48757c0 100644 --- a/src/flamenco/runtime/fd_runtime_init.c +++ b/src/flamenco/runtime/fd_runtime_init.c @@ -1,9 +1,7 @@ #include "fd_runtime_init.h" -#include "fd_runtime_err.h" -#include +#include "fd_acc_mgr.h" #include "../types/fd_types.h" #include "context/fd_exec_slot_ctx.h" -#include "../../ballet/lthash/fd_lthash.h" #include "fd_system_ids.h" /* fd_feature_restore loads a feature from the accounts database and diff --git a/src/flamenco/runtime/program/fd_address_lookup_table_program.c b/src/flamenco/runtime/program/fd_address_lookup_table_program.c index 85985727f6..0c6d655cb7 100644 --- a/src/flamenco/runtime/program/fd_address_lookup_table_program.c +++ b/src/flamenco/runtime/program/fd_address_lookup_table_program.c @@ -3,9 +3,9 @@ #include "../fd_pubkey_utils.h" #include "../fd_borrowed_account.h" #include "../sysvar/fd_sysvar_slot_hashes.h" -#include "../sysvar/fd_sysvar_clock.h" #include "../../vm/syscall/fd_vm_syscall.h" #include "fd_native_cpi.h" +#include "../fd_runtime_err.h" #include @@ -107,7 +107,8 @@ fd_addrlut_serialize_meta( fd_address_lookup_table_state_t const * state, } static ulong -slot_hashes_position( fd_slot_hash_t const * hashes, ulong slot ) { +slot_hashes_position( fd_slot_hash_t const * hashes, /* deque */ + ulong slot ) { /* Logic is copied from slice::binary_search_by() in Rust. While not fully optimized, it aims to achieve fuzzing conformance for both sorted and unsorted inputs. Returns the slot hash position of the input slot. */ @@ -130,7 +131,7 @@ slot_hashes_position( fd_slot_hash_t const * hashes, ulong slot ) { static uchar fd_addrlut_status( fd_lookup_table_meta_t const * state, ulong current_slot, - fd_slot_hash_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ ulong * remaining_blocks ) { /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L82-L83 */ if( state->deactivation_slot==ULONG_MAX ) { @@ -252,14 +253,11 @@ create_lookup_table( fd_exec_instr_ctx_t * ctx, ulong derivation_slot = 1UL; do { - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - - if( FD_UNLIKELY( !slot_hashes_global ) ) { + fd_slot_hash_t const * slot_hash = fd_sysvar_slot_hashes_join_const( ctx->sysvar_cache ); + if( FD_UNLIKELY( !slot_hash ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } - fd_slot_hash_t * slot_hash = deq_fd_slot_hash_t_join( (uchar*)slot_hashes_global + slot_hashes_global->hashes_offset ); - /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L97 */ ulong is_recent_slot = slot_hashes_position( slot_hash, create->recent_slot )!=ULONG_MAX; if( FD_UNLIKELY( !is_recent_slot ) ) { @@ -300,11 +298,11 @@ create_lookup_table( fd_exec_instr_ctx_t * ctx, /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L137-L142 */ - fd_rent_t const * rent = fd_bank_rent_query( ctx->txn_ctx->bank ); - ulong tbl_acct_data_len = 0x38UL; - ulong required_lamports = fd_rent_exempt_minimum_balance( rent, tbl_acct_data_len ); - required_lamports = fd_ulong_max( required_lamports, 1UL ); - required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail( ctx->sysvar_cache ); + ulong tbl_acct_data_len = 0x38UL; + ulong required_lamports = fd_rent_exempt_minimum_balance( &rent, tbl_acct_data_len ); + /* */ required_lamports = fd_ulong_max( required_lamports, 1UL ); + /* */ required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports ); /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L144-L149 */ if( required_lamports>0UL ) { @@ -670,7 +668,8 @@ extend_lookup_table( fd_exec_instr_ctx_t * ctx, } /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L290 */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } @@ -713,10 +712,13 @@ extend_lookup_table( fd_exec_instr_ctx_t * ctx, /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L317-L321 */ - fd_rent_t const * rent = fd_bank_rent_query( ctx->txn_ctx->bank ); - ulong required_lamports = fd_rent_exempt_minimum_balance( rent, new_table_data_sz ); - required_lamports = fd_ulong_max ( required_lamports, 1UL ); - required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports ); + fd_rent_t rent[1]; + if( FD_UNLIKELY( !fd_sysvar_rent_read( ctx->sysvar_cache, rent ) ) ) { + FD_LOG_ERR(( "fd_sysvar_rent_read failed" )); + } + ulong required_lamports = fd_rent_exempt_minimum_balance( rent, new_table_data_sz ); + /* */ required_lamports = fd_ulong_max ( required_lamports, 1UL ); + /* */ required_lamports = fd_ulong_sat_sub( required_lamports, lut_lamports ); if( required_lamports ) { fd_pubkey_t const * payer_key = NULL; @@ -867,7 +869,8 @@ deactivate_lookup_table( fd_exec_instr_ctx_t * ctx ) { } /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L380 */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } @@ -986,19 +989,18 @@ close_lookup_table( fd_exec_instr_ctx_t * ctx ) { } /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L437 */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L438 */ - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !slot_hashes_global ) ) { + fd_slot_hash_t const * slot_hash = fd_sysvar_slot_hashes_join_const( ctx->sysvar_cache ); + if( FD_UNLIKELY( !slot_hash ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } - fd_slot_hash_t * slot_hash = deq_fd_slot_hash_t_join( (uchar*)slot_hashes_global + slot_hashes_global->hashes_offset ); - /* https://github.com/solana-labs/solana/blob/v1.17.4/programs/address-lookup-table/src/processor.rs#L440 */ ulong remaining_blocks = 0UL; int status = fd_addrlut_status( &state->meta, clock->slot, slot_hash, &remaining_blocks ); @@ -1112,7 +1114,7 @@ fd_address_lookup_table_program_execute( fd_exec_instr_ctx_t * ctx ) { static uchar is_active( fd_address_lookup_table_t const * self, ulong current_slot, - fd_slot_hash_t const * slot_hashes ) { + fd_slot_hash_t const * slot_hashes ) { /* deque */ /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L73-L77 */ ulong _dummy[1]; switch( fd_addrlut_status( &self->meta, current_slot, slot_hashes, _dummy ) ) { @@ -1131,7 +1133,7 @@ is_active( fd_address_lookup_table_t const * self, int fd_get_active_addresses_len( fd_address_lookup_table_t * self, ulong current_slot, - fd_slot_hash_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ ulong addresses_len, ulong * active_addresses_len ) { /* https://github.com/anza-xyz/agave/blob/368ea563c423b0a85cc317891187e15c9a321521/sdk/program/src/address_lookup_table/state.rs#L147-L152 */ diff --git a/src/flamenco/runtime/program/fd_bpf_loader_program.c b/src/flamenco/runtime/program/fd_bpf_loader_program.c index 2c6747d685..a1a3e8baad 100644 --- a/src/flamenco/runtime/program/fd_bpf_loader_program.c +++ b/src/flamenco/runtime/program/fd_bpf_loader_program.c @@ -3,9 +3,8 @@ /* For additional context see https://solana.com/docs/programs/deploying#state-accounts */ #include "../fd_pubkey_utils.h" -#include "../../../ballet/base58/fd_base58.h" #include "../../../ballet/sbpf/fd_sbpf_loader.h" -#include "../sysvar/fd_sysvar_clock.h" +#include "../sysvar/fd_sysvar.h" #include "../sysvar/fd_sysvar_rent.h" #include "../../vm/syscall/fd_vm_syscall.h" #include "../../vm/fd_vm.h" @@ -770,7 +769,8 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { return err; } - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR; } @@ -792,7 +792,7 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { fd_bpf_upgradeable_loader_state_t * loader_state = NULL; fd_pubkey_t * new_program_id = NULL; - fd_rent_t const * rent = fd_bank_rent_query( instr_ctx->txn_ctx->bank ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail( instr_ctx->sysvar_cache ); /* https://github.com/anza-xyz/agave/blob/v2.1.4/programs/bpf_loader/src/lib.rs#L545 */ fd_guarded_borrowed_account_t program; @@ -813,8 +813,8 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { fd_log_collector_msg_literal( instr_ctx, "Program account too small" ); return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL; } - if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &program )txn_ctx->bank ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail( instr_ctx->sysvar_cache ); - programdata_balance_required = fd_ulong_max( 1UL, fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &programdata ) ) ); + programdata_balance_required = fd_ulong_max( 1UL, fd_rent_exempt_minimum_balance( &rent, fd_borrowed_account_get_data_len( &programdata ) ) ); if( FD_UNLIKELY( fd_borrowed_account_get_data_len( &programdata )txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_GENERIC_ERR; } @@ -1633,7 +1634,8 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { fd_log_collector_msg_literal( instr_ctx, "Program account not owned by loader" ); return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID; } - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } @@ -1753,7 +1755,8 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { "Extended ProgramData length of %lu bytes exceeds max account data length of %lu bytes", new_len, MAX_PERMITTED_DATA_LENGTH ); return FD_EXECUTOR_INSTR_ERR_INVALID_REALLOC; } - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } @@ -1780,10 +1783,10 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { } /* https://github.com/anza-xyz/agave/blob/574bae8fefc0ed256b55340b9d87b7689bcdf222/programs/bpf_loader/src/lib.rs#L1232-L1256 */ - fd_rent_t const * rent = fd_bank_rent_query( instr_ctx->txn_ctx->bank ); - ulong balance = fd_borrowed_account_get_lamports( &programdata_account ); - ulong min_balance = fd_ulong_max( fd_rent_exempt_minimum_balance( rent, new_len ), 1UL ); - ulong required_payment = fd_ulong_sat_sub( min_balance, balance ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail( instr_ctx->sysvar_cache ); + ulong balance = fd_borrowed_account_get_lamports( &programdata_account ); + ulong min_balance = fd_ulong_max( fd_rent_exempt_minimum_balance( &rent, new_len ), 1UL ); + ulong required_payment = fd_ulong_sat_sub( min_balance, balance ); /* Borrowed accounts need to be dropped before native invocations. Note: the programdata account is manually released and acquired within the @@ -1928,7 +1931,8 @@ process_loader_upgradeable_instruction( fd_exec_instr_ctx_t * instr_ctx ) { } /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/bpf_loader/src/lib.rs#L1356-L1359 */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } diff --git a/src/flamenco/runtime/program/fd_bpf_program_util.c b/src/flamenco/runtime/program/fd_bpf_program_util.c index 4de5bc7f6e..22263c016b 100644 --- a/src/flamenco/runtime/program/fd_bpf_program_util.c +++ b/src/flamenco/runtime/program/fd_bpf_program_util.c @@ -235,10 +235,7 @@ fd_bpf_validate_sbpf_program( fd_exec_slot_ctx_t const * slot_ctx, fd_sbpf_validated_program_t * validated_prog /* out */ ) { /* Mark the program as validated for this epoch. */ - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - validated_prog->last_epoch_verification_ran = fd_slot_to_epoch( epoch_schedule, - fd_bank_slot_get( slot_ctx->bank ), - NULL ); + validated_prog->last_epoch_verification_ran = fd_bank_epoch_get( slot_ctx->bank ); ulong prog_align = fd_sbpf_program_align(); ulong prog_footprint = fd_sbpf_program_footprint( elf_info ); @@ -553,8 +550,7 @@ FD_SPAD_FRAME_BEGIN( runtime_spad ) { /* At this point, the program is in the cache. We need to check the last verified epoch now to determine if it needs to be reverified. If it has already been reverified for the current epoch, then there is no need to do anything. */ - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong current_epoch = fd_slot_to_epoch( epoch_schedule, fd_bank_slot_get( slot_ctx->bank ), NULL ); + ulong current_epoch = fd_bank_epoch_get(slot_ctx->bank ); if( FD_LIKELY( prog->last_epoch_verification_ran==current_epoch ) ) { return; } diff --git a/src/flamenco/runtime/program/fd_loader_v4_program.c b/src/flamenco/runtime/program/fd_loader_v4_program.c index bcdf49ab6f..38cffee5ae 100644 --- a/src/flamenco/runtime/program/fd_loader_v4_program.c +++ b/src/flamenco/runtime/program/fd_loader_v4_program.c @@ -1,5 +1,4 @@ #include "fd_loader_v4_program.h" -#include "../sysvar/fd_sysvar_clock.h" /* Helper functions that would normally be provided by fd_types. */ FD_FN_PURE uchar @@ -334,11 +333,12 @@ fd_loader_v4_program_instruction_set_program_length( fd_exec_instr_ctx_t * } /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L221-L227 */ - fd_rent_t const * rent = fd_sysvar_rent_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); - - if( FD_UNLIKELY( rent==NULL ) ) { + fd_rent_t rent_; + fd_rent_t const * rent = fd_sysvar_rent_read( instr_ctx->sysvar_cache, &rent_ ); + if( FD_UNLIKELY( !rent ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } + ulong new_program_dlen = fd_ulong_sat_add( LOADER_V4_PROGRAM_DATA_OFFSET, new_size ); ulong required_lamports = ( new_size==0UL ) ? 0UL : @@ -469,8 +469,9 @@ fd_loader_v4_program_instruction_deploy( fd_exec_instr_ctx_t * instr_ctx ) { } /* https://github.com/anza-xyz/agave/blob/v2.2.13/programs/loader-v4/src/lib.rs#L288 */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( clock==NULL ) ) { + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } ulong current_slot = clock->slot; @@ -563,8 +564,9 @@ fd_loader_v4_program_instruction_retract( fd_exec_instr_ctx_t * instr_ctx ) { } /* https://github.com/anza-xyz/agave/blob/v2.2.6/programs/loader-v4/src/lib.rs#L368 */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( clock==NULL ) ) { + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } ulong current_slot = clock->slot; diff --git a/src/flamenco/runtime/program/fd_stake_program.c b/src/flamenco/runtime/program/fd_stake_program.c index 5106bd6fe4..6f889372a4 100644 --- a/src/flamenco/runtime/program/fd_stake_program.c +++ b/src/flamenco/runtime/program/fd_stake_program.c @@ -10,9 +10,8 @@ #include "fd_vote_program.h" #include "../sysvar/fd_sysvar_epoch_schedule.h" #include "../sysvar/fd_sysvar_rent.h" -#include "../sysvar/fd_sysvar_stake_history.h" -#include "../sysvar/fd_sysvar_clock.h" -#include "../sysvar/fd_sysvar_epoch_rewards.h" +#include "../sysvar/fd_sysvar.h" + /* A note on fd_borrowed_account_acquire_write: The stake program uses this function to prevent aliasing of accounts. @@ -282,9 +281,9 @@ validate_split_amount( fd_exec_instr_ctx_t const * invoke_context, }; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1042 - fd_rent_t const * rent = fd_sysvar_rent_read( invoke_context->txn_ctx->funk, invoke_context->txn_ctx->funk_txn, invoke_context->txn_ctx->spad ); - if( FD_UNLIKELY( !rent ) ) - return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_rent_t rent_; + fd_rent_t const * rent = fd_sysvar_rent_read( invoke_context->sysvar_cache, &rent_ ); + if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1043 ulong destination_rent_exempt_reserve = @@ -748,21 +747,23 @@ stake_deactivate( fd_stake_t * stake, ulong epoch, uint * custom_err ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L62 int -fd_new_warmup_cooldown_rate_epoch( ulong slot, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad, - fd_features_t const * features, - /* out */ ulong * epoch, - int * err ) { +fd_new_warmup_cooldown_rate_epoch( + fd_sysvar_cache_t const * sysvar_cache, + fd_features_t const * features, + ulong slot, + /* out */ ulong * epoch, + int * err +) { *err = 0; - fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, spad ); + fd_epoch_schedule_t epoch_schedule_; + fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( sysvar_cache, &epoch_schedule_ ); if( FD_UNLIKELY( !epoch_schedule ) ) { *epoch = ULONG_MAX; *err = FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; return 1; } + /* reduce_stake_warmup_cooldown is activated on all clusters, so we shouldn't have a `None` case. */ if( FD_LIKELY( FD_FEATURE_ACTIVE( slot, features, reduce_stake_warmup_cooldown ) ) ) { ulong slot = features->reduce_stake_warmup_cooldown; @@ -832,15 +833,14 @@ get_if_mergeable( fd_exec_instr_ctx_t * invoke_context, // not const to fd_stake_flags_t const * stake_flags = &stake_state->inner.stake.stake_flags; ulong new_rate_activation_epoch = ULONG_MAX; - int err; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1111 - int is_some = fd_new_warmup_cooldown_rate_epoch( invoke_context->txn_ctx->slot, - invoke_context->txn_ctx->funk, - invoke_context->txn_ctx->funk_txn, - invoke_context->txn_ctx->spad, - &invoke_context->txn_ctx->features, - &new_rate_activation_epoch, - &err ); + int err; + int is_some = fd_new_warmup_cooldown_rate_epoch( + invoke_context->sysvar_cache, + &invoke_context->txn_ctx->features, + invoke_context->txn_ctx->slot, + &new_rate_activation_epoch, + &err ); if( FD_UNLIKELY( err ) ) return err; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1108 @@ -1144,31 +1144,35 @@ get_stake_status( fd_exec_instr_ctx_t const * invoke_context, fd_stake_t * stake, fd_sol_sysvar_clock_t const * clock, fd_stake_activation_status_t * out ) { - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( invoke_context->txn_ctx->funk, invoke_context->txn_ctx->funk_txn, invoke_context->txn_ctx->spad ); - if( FD_UNLIKELY( !stake_history ) ) + fd_sysvar_cache_t const * sysvar_cache = invoke_context->sysvar_cache; + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( sysvar_cache ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + } + ulong new_rate_activation_epoch = ULONG_MAX; - int err; - int is_some = fd_new_warmup_cooldown_rate_epoch( invoke_context->txn_ctx->slot, - invoke_context->txn_ctx->funk, - invoke_context->txn_ctx->funk_txn, - invoke_context->txn_ctx->spad, - &invoke_context->txn_ctx->features, - &new_rate_activation_epoch, - &err ); + int err; + int is_some = fd_new_warmup_cooldown_rate_epoch( + sysvar_cache, + &invoke_context->txn_ctx->features, + invoke_context->txn_ctx->slot, + &new_rate_activation_epoch, + &err ); if( FD_UNLIKELY( err ) ) return err; - *out = - stake_activating_and_deactivating( &stake->delegation, - clock->epoch, - stake_history, - fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) ); + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( sysvar_cache ); + *out = stake_activating_and_deactivating( + &stake->delegation, + clock->epoch, + stake_history, + fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) ); + fd_sysvar_stake_history_leave_const( sysvar_cache, stake_history ); + return 0; } // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/vote/state/mod.rs#L740 static ulong -get_credits( fd_vote_state_t const * vote_state ) { +get_credits( fd_vote_state_t const * vote_state ) { return ( deq_fd_vote_epoch_credits_t_empty( vote_state->epoch_credits ) ? 0 @@ -1189,14 +1193,13 @@ redelegate_stake( fd_exec_instr_ctx_t const * ctx, fd_stake_history_t const * stake_history, uint * custom_err ) { ulong new_rate_activation_epoch = ULONG_MAX; - int err; - int is_some = fd_new_warmup_cooldown_rate_epoch( ctx->txn_ctx->slot, - ctx->txn_ctx->funk, - ctx->txn_ctx->funk_txn, - ctx->txn_ctx->spad, - &ctx->txn_ctx->features, - &new_rate_activation_epoch, - &err ); + int err; + int is_some = fd_new_warmup_cooldown_rate_epoch( + ctx->sysvar_cache, + &ctx->txn_ctx->features, + ctx->txn_ctx->slot, + &new_rate_activation_epoch, + &err ); if( FD_UNLIKELY( err ) ) return err; // FIXME FD_LIKELY @@ -1629,9 +1632,9 @@ split( fd_exec_instr_ctx_t const * ctx, int is_active; if( FD_UNLIKELY( FD_FEATURE_ACTIVE_BANK( ctx->txn_ctx->bank, require_rent_exempt_split_destination ) ) ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L434 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !clock ) ) - return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L435 fd_stake_activation_status_t status = {0}; @@ -1958,13 +1961,12 @@ move_stake_or_lamports_shared_checks( fd_exec_instr_ctx_t * invoke_context, // return FD_EXECUTOR_INSTR_ERR_INVALID_ARG; // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L177-L180 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( invoke_context->txn_ctx->funk, invoke_context->txn_ctx->funk_txn, invoke_context->txn_ctx->spad ); - if( FD_UNLIKELY( !clock ) ) - return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( invoke_context->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( invoke_context->txn_ctx->funk, invoke_context->txn_ctx->funk_txn, invoke_context->txn_ctx->spad ); - if( FD_UNLIKELY( !stake_history ) ) - return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( invoke_context->sysvar_cache ); + if( FD_UNLIKELY( !stake_history ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L182 fd_stake_state_v2_t source_account_state = {0}; @@ -2557,14 +2559,7 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { /* The EpochRewards sysvar only exists after partitioned epoch rewards is activated. If the sysvar exists, check the `active` field */ - int epoch_rewards_active = 0; - - fd_sysvar_epoch_rewards_t * epoch_rewards = fd_sysvar_epoch_rewards_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad );{ - if( FD_LIKELY( epoch_rewards ) ) { - epoch_rewards_active = epoch_rewards->active; - } - } - + int epoch_rewards_active = !!fd_sysvar_epoch_rewards_is_valid( ctx->sysvar_cache ); if( epoch_rewards_active && instruction->discriminant!=fd_stake_instruction_enum_get_minimum_delegation ) { ctx->txn_ctx->custom_err = FD_STAKE_ERR_EPOCH_REWARDS_ACTIVE; return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; @@ -2598,7 +2593,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L87 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_rent_t const * rent = fd_sysvar_rent_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_rent_t rent_; + fd_rent_t const * rent = fd_sysvar_rent_read( ctx->sysvar_cache, &rent_ ); if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L88 @@ -2628,7 +2624,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L92 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L94 if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) ) @@ -2673,7 +2670,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L110 rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L112 fd_pubkey_t const * custodian_pubkey = NULL; @@ -2715,13 +2713,15 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L131 rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L133 rc = fd_sysvar_instr_acct_check( ctx, 3, &fd_sysvar_stake_history_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !stake_history ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( ctx->sysvar_cache ) ) ) { + return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + } // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L138 if( FD_UNLIKELY( ctx->instr->acct_cnt<5 ) ) return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; @@ -2730,13 +2730,14 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { fd_borrowed_account_drop( &me ); // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L140 + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( ctx->sysvar_cache ); rc = delegate( ctx, 0, 1, clock, stake_history, signers ); - + fd_sysvar_stake_history_leave_const( ctx->sysvar_cache, stake_history ); break; } @@ -2786,19 +2787,23 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L169 rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L171 rc = fd_sysvar_instr_acct_check( ctx, 3, &fd_sysvar_stake_history_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !stake_history ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( ctx->sysvar_cache ) ) ) { + return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + } /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/stake/src/stake_instruction.rs#L175 */ fd_borrowed_account_drop( &me ); // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L177 + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( ctx->sysvar_cache ); rc = merge( ctx, 0, 1, clock, stake_history, signers ); + fd_sysvar_stake_history_leave_const( ctx->sysvar_cache, stake_history ); break; } @@ -2823,13 +2828,15 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L191 rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L193 rc = fd_sysvar_instr_acct_check( ctx, 3, &fd_sysvar_stake_history_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_stake_history_t const * stake_history = fd_sysvar_stake_history_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !stake_history ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( ctx->sysvar_cache ) ) ) { + return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + } // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L198 if( FD_UNLIKELY( ctx->instr->acct_cnt<5 ) ) return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; @@ -2840,16 +2847,15 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { uchar custodian_index = 5; ulong new_rate_activation_epoch = ULONG_MAX; int err; - int is_some = fd_new_warmup_cooldown_rate_epoch( ctx->txn_ctx->slot, - ctx->txn_ctx->funk, - ctx->txn_ctx->funk_txn, - ctx->txn_ctx->spad, + int is_some = fd_new_warmup_cooldown_rate_epoch( ctx->sysvar_cache, &ctx->txn_ctx->features, + ctx->txn_ctx->slot, &new_rate_activation_epoch, &err ); if( FD_UNLIKELY( err ) ) return err; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L200 + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( ctx->sysvar_cache ); rc = withdraw( ctx, 0, @@ -2861,6 +2867,7 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L209-L215 fd_ptr_if( ctx->instr->acct_cnt>=6, &custodian_index, NULL ), fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) ); + fd_sysvar_stake_history_leave_const( ctx->sysvar_cache, stake_history ); } FD_SPAD_FRAME_END; /* No real allocations. Just logically whatever alloc there is, this is where their life ends. */ break; @@ -2881,7 +2888,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L219 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L221 @@ -2907,7 +2915,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { rc = get_stake_account( ctx, &me ); if( FD_UNLIKELY( rc ) ) return rc; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L225 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L226 @@ -2952,7 +2961,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L246 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_rent_t const * rent = fd_sysvar_rent_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_rent_t rent_; + fd_rent_t const * rent = fd_sysvar_rent_read( ctx->sysvar_cache, &rent_ ); if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; fd_stake_lockup_t lockup_default = {0}; @@ -2982,7 +2992,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L251 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L253 if( FD_UNLIKELY( ctx->instr->acct_cnt<4 ) ) @@ -3035,7 +3046,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L276 rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L277 if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( ctx, 4U) ) ) @@ -3093,9 +3105,9 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { .epoch = lockup_checked->epoch, .custodian = (fd_pubkey_t *)custodian_pubkey }; // FIXME // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L310 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !clock ) ) - return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L311 rc = set_lockup( &me, &lockup, signers, clock ); @@ -3136,9 +3148,9 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) ) return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L325 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !clock ) ) - return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L326 rc = deactivate_delinquent( ctx, &me, 1, 2, clock->epoch, &ctx->txn_ctx->custom_err ); diff --git a/src/flamenco/runtime/program/fd_stake_program.h b/src/flamenco/runtime/program/fd_stake_program.h index 08b7ffc7c8..7dcd45cfa5 100644 --- a/src/flamenco/runtime/program/fd_stake_program.h +++ b/src/flamenco/runtime/program/fd_stake_program.h @@ -17,13 +17,13 @@ FD_PROTOTYPES_BEGIN int -fd_new_warmup_cooldown_rate_epoch( ulong slot, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad, - fd_features_t const * features, - /* out */ ulong * epoch, - int * err ); +fd_new_warmup_cooldown_rate_epoch( + fd_sysvar_cache_t const * sysvar_cache, + fd_features_t const * features, + ulong slot, + /* out */ ulong * out_epoch, + int * err +); /* fd_stake_program_execute is the instruction processing entrypoint for the stake program. On return, ctx.txn_ctx->dirty_stake_acc==1 if diff --git a/src/flamenco/runtime/program/fd_system_program_nonce.c b/src/flamenco/runtime/program/fd_system_program_nonce.c index 0437f48b96..c4d875b315 100644 --- a/src/flamenco/runtime/program/fd_system_program_nonce.c +++ b/src/flamenco/runtime/program/fd_system_program_nonce.c @@ -2,11 +2,11 @@ #include "../fd_borrowed_account.h" #include "../fd_acc_mgr.h" #include "../fd_system_ids.h" -#include "../context/fd_exec_slot_ctx.h" #include "../context/fd_exec_txn_ctx.h" -#include "../sysvar/fd_sysvar_rent.h" #include "../sysvar/fd_sysvar_recent_hashes.h" +#include "../sysvar/fd_sysvar_rent.h" #include "../fd_executor.h" +#include "../fd_runtime_err.h" static int require_acct( fd_exec_instr_ctx_t * ctx, @@ -34,7 +34,8 @@ require_acct_rent( fd_exec_instr_ctx_t * ctx, if( FD_UNLIKELY( err ) ) return err; } while(0); - fd_rent_t const * rent = fd_sysvar_rent_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_rent_t rent_; + fd_rent_t const * rent = fd_sysvar_rent_read( ctx->sysvar_cache, &rent_ ); if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; @@ -43,22 +44,18 @@ require_acct_rent( fd_exec_instr_ctx_t * ctx, } static int -require_acct_recent_blockhashes( fd_exec_instr_ctx_t * ctx, - ushort idx, - fd_recent_block_hashes_t * * out ) { +require_acct_recent_blockhashes( fd_exec_instr_ctx_t * ctx, + ushort idx ) { do { int err = require_acct( ctx, idx, &fd_sysvar_recent_block_hashes_id ); if( FD_UNLIKELY( err ) ) return err; } while(0); - fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !rbh_global ) ) { + if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( ctx->sysvar_cache ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } - (*out)->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset ); - return FD_EXECUTOR_INSTR_SUCCESS; } @@ -73,9 +70,9 @@ most_recent_block_hash( fd_exec_instr_ctx_t * ctx, /* The environment config blockhash comes from `bank.last_blockhash_and_lamports_per_signature()`, which takes the top element from the blockhash queue. https://github.com/anza-xyz/agave/blob/v2.1.6/programs/system/src/system_instruction.rs#L47 */ - fd_block_hash_queue_global_t const * block_hash_queue = fd_bank_block_hash_queue_query( ctx->txn_ctx->bank ); - fd_hash_t const * last_hash = fd_block_hash_queue_last_hash_join( block_hash_queue ); - if( FD_UNLIKELY( last_hash==NULL ) ) { + fd_blockhashes_t const * block_hash_queue = fd_bank_block_hash_queue_query( ctx->txn_ctx->bank ); + fd_hash_t const * last_hash = fd_blockhashes_peek_last( block_hash_queue ); + if( FD_UNLIKELY( !last_hash ) ) { // Agave panics if this blockhash was never set at the start of the txn batch ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES; return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; @@ -245,6 +242,20 @@ fd_system_program_advance_nonce_account( fd_exec_instr_ctx_t * ctx, return FD_EXECUTOR_INSTR_SUCCESS; } +/* recent_blockhashes_is_empty returns 1 if the recent blockhashes + sysvar is empty, 0 otherwise. Assumes that sysvar is valid. This + function only exists because the fd_types API is horrible and serves + to hide away the mess. */ + +static int +recent_blockhashes_is_empty( fd_sysvar_cache_t const * sysvar_cache ) { + fd_block_block_hash_entry_t const * hashes = fd_sysvar_recent_hashes_join_const( sysvar_cache ); + if( FD_UNLIKELY( !hashes ) ) FD_LOG_CRIT(( "Recent blockhashes sysvar is not initialized" )); /* unreachable */ + int const is_empty = deq_fd_block_block_hash_entry_t_empty( hashes ); + fd_sysvar_recent_hashes_leave_const( sysvar_cache, hashes ); + return is_empty; +} + /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L423-L441 Matches Solana Labs system_processor SystemInstruction::AdvanceNonceAccount => { ... } */ @@ -268,18 +279,14 @@ fd_system_program_exec_advance_nonce_account( fd_exec_instr_ctx_t * ctx ) { /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L427-L432 */ - fd_recent_block_hashes_t recent_blockhashes_obj; - fd_recent_block_hashes_t * recent_blockhashes = &recent_blockhashes_obj; do { - err = require_acct_recent_blockhashes( ctx, 1UL, &recent_blockhashes ); + err = require_acct_recent_blockhashes( ctx, 1UL ); if( FD_UNLIKELY( err ) ) return err; } while(0); - fd_block_block_hash_entry_t const * hashes = recent_blockhashes->hashes; - /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L433-L439 */ - if( FD_UNLIKELY( deq_fd_block_block_hash_entry_t_empty( hashes ) ) ) { + if( FD_UNLIKELY( recent_blockhashes_is_empty( ctx->sysvar_cache ) ) ) { fd_log_collector_msg_literal( ctx, "Advance nonce account: recent blockhash list is empty" ); ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES; return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; @@ -480,10 +487,8 @@ fd_system_program_exec_withdraw_nonce_account( fd_exec_instr_ctx_t * ctx, /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L445-L449 */ - fd_recent_block_hashes_t recent_blockhashes_obj; - fd_recent_block_hashes_t * recent_blockhashes = &recent_blockhashes_obj; do { - int err = require_acct_recent_blockhashes( ctx, 2UL, &recent_blockhashes ); + int err = require_acct_recent_blockhashes( ctx, 2UL ); if( FD_UNLIKELY( err ) ) return err; } while(0); @@ -633,18 +638,14 @@ fd_system_program_exec_initialize_nonce_account( fd_exec_instr_ctx_t * ctx, /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L466-L471 */ - fd_recent_block_hashes_t recent_blockhashes_obj; - fd_recent_block_hashes_t * recent_blockhashes = &recent_blockhashes_obj; do { - err = require_acct_recent_blockhashes( ctx, 1UL, &recent_blockhashes ); + err = require_acct_recent_blockhashes( ctx, 1UL ); if( FD_UNLIKELY( err ) ) return err; } while(0); - fd_block_block_hash_entry_t const * hashes = recent_blockhashes->hashes; - /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L472-L478 */ - if( FD_UNLIKELY( deq_fd_block_block_hash_entry_t_empty( hashes ) ) ) { + if( FD_UNLIKELY( recent_blockhashes_is_empty( ctx->sysvar_cache ) ) ) { fd_log_collector_msg_literal( ctx, "Initialize nonce account: recent blockhash list is empty" ); ctx->txn_ctx->custom_err = FD_SYSTEM_PROGRAM_ERR_NONCE_NO_RECENT_BLOCKHASHES; return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; @@ -877,8 +878,12 @@ fd_system_program_exec_upgrade_nonce_account( fd_exec_instr_ctx_t * ctx ) { Note: We check 151 and not 150 due to a known bug in agave. */ int fd_check_transaction_age( fd_exec_txn_ctx_t * txn_ctx ) { - fd_block_hash_queue_global_t const * block_hash_queue = fd_bank_block_hash_queue_query( txn_ctx->bank ); - fd_hash_t * last_blockhash = fd_block_hash_queue_last_hash_join( block_hash_queue ); + fd_blockhashes_t const * block_hash_queue = fd_bank_block_hash_queue_query( txn_ctx->bank ); + fd_hash_t const * last_blockhash = fd_blockhashes_peek_last( block_hash_queue ); + if( FD_UNLIKELY( !last_blockhash ) ) { + /* FIXME What does Agave do here? */ + return FD_RUNTIME_TXN_ERR_BLOCKHASH_NOT_FOUND; + } /* check_transaction_age */ fd_hash_t next_durable_nonce = {0}; @@ -890,7 +895,7 @@ fd_check_transaction_age( fd_exec_txn_ctx_t * txn_ctx ) { /* get_hash_info_if_valid. Check 151 hashes from the block hash queue and its age to see if it is valid. */ - if( fd_executor_is_blockhash_valid_for_age( block_hash_queue, recent_blockhash, FD_RECENT_BLOCKHASHES_MAX_ENTRIES ) ) { + if( fd_blockhashes_check_age( block_hash_queue, recent_blockhash, FD_SYSVAR_RECENT_HASHES_CAP ) ) { return FD_RUNTIME_EXECUTE_SUCCESS; } diff --git a/src/flamenco/runtime/program/fd_vote_program.c b/src/flamenco/runtime/program/fd_vote_program.c index 75c4ebcba9..5a7078e955 100644 --- a/src/flamenco/runtime/program/fd_vote_program.c +++ b/src/flamenco/runtime/program/fd_vote_program.c @@ -1,12 +1,9 @@ #include "fd_vote_program.h" -#include "../../types/fd_types_yaml.h" #include "../fd_borrowed_account.h" #include "../fd_executor.h" #include "../fd_pubkey_utils.h" -#include "../sysvar/fd_sysvar_epoch_schedule.h" #include "../sysvar/fd_sysvar_rent.h" -#include "../sysvar/fd_sysvar_clock.h" -#include "../sysvar/fd_sysvar_slot_hashes.h" +#include "../sysvar/fd_sysvar.h" #include #include @@ -795,9 +792,9 @@ set_vote_account_state( fd_borrowed_account_t * vote_account, ulong vsz = size_of_versioned( 1 ); // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L175 - fd_rent_t const * rent = fd_bank_rent_query( ctx->txn_ctx->bank ); - int resize_needed = fd_borrowed_account_get_data_len( vote_account ) < vsz; - int resize_rent_exempt = fd_rent_exempt_minimum_balance( rent, vsz ) <= fd_borrowed_account_get_lamports( vote_account ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail( ctx->sysvar_cache ); + int resize_needed = fd_borrowed_account_get_data_len( vote_account ) < vsz; + int resize_rent_exempt = fd_rent_exempt_minimum_balance( &rent, vsz ) <= fd_borrowed_account_get_lamports( vote_account ); /* The resize operation itself is part of the horrible conditional, but behind a short-circuit operator. */ @@ -866,7 +863,7 @@ check_and_filter_proposed_vote_state( fd_vote_state_t * vote_state, uchar * proposed_has_root, ulong * proposed_root, fd_hash_t const * proposed_hash, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ fd_exec_instr_ctx_t const * ctx ) { // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L208 if( FD_UNLIKELY( deq_fd_vote_lockout_t_empty( proposed_lockouts ) ) ) { @@ -891,13 +888,13 @@ check_and_filter_proposed_vote_state( fd_vote_state_t * vote_state, ulong last_vote_state_update_slot = deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L224 - if( FD_UNLIKELY( deq_fd_slot_hash_t_empty( slot_hashes->hashes ) ) ) { + if( FD_UNLIKELY( deq_fd_slot_hash_t_empty( slot_hashes ) ) ) { ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_MISMATCH; return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L227 - ulong earliest_slot_hash_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes->hashes )->slot; + ulong earliest_slot_hash_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes )->slot; /* Check if the proposed vote is too old to be in the SlotHash history */ // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L230 @@ -947,7 +944,7 @@ check_and_filter_proposed_vote_state( fd_vote_state_t * vote_state, /* Index into the slot_hashes, starting at the oldest known slot hash */ // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L264 - ulong slot_hashes_index = deq_fd_slot_hash_t_cnt( slot_hashes->hashes ); + ulong slot_hashes_index = deq_fd_slot_hash_t_cnt( slot_hashes ); ulong * proposed_lockouts_indexes_to_filter = fd_spad_alloc( ctx->txn_ctx->spad, alignof(ulong), lockouts_len * sizeof(ulong) ); ulong filter_index = 0UL; @@ -992,7 +989,7 @@ check_and_filter_proposed_vote_state( fd_vote_state_t * vote_state, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L295 ulong ancestor_slot = deq_fd_slot_hash_t_peek_index_const( - slot_hashes->hashes, + slot_hashes, fd_ulong_checked_sub_expect( slot_hashes_index, 1UL, @@ -1002,7 +999,7 @@ check_and_filter_proposed_vote_state( fd_vote_state_t * vote_state, to confirm if it was a valid ancestor on this fork */ // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L303 if( proposed_vote_slot < ancestor_slot ) { - if( slot_hashes_index == deq_fd_slot_hash_t_cnt( slot_hashes->hashes ) ) { + if( slot_hashes_index == deq_fd_slot_hash_t_cnt( slot_hashes ) ) { /* The vote slot does not exist in the SlotHashes history because it's too old, i.e. older than the oldest slot in the history. */ if( proposed_vote_slot >= earliest_slot_hash_in_history ) { @@ -1096,7 +1093,7 @@ check_and_filter_proposed_vote_state( fd_vote_state_t * vote_state, } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L401 - if( memcmp( &deq_fd_slot_hash_t_peek_index_const( slot_hashes->hashes, slot_hashes_index )->hash, + if( memcmp( &deq_fd_slot_hash_t_peek_index_const( slot_hashes, slot_hashes_index )->hash, proposed_hash, sizeof( fd_hash_t ) ) != 0 ) { /* This means the newest vote in the slot has a match that @@ -1134,10 +1131,10 @@ static int check_slots_are_valid( fd_vote_state_t * vote_state, ulong const * vote_slots, fd_hash_t const * vote_hash, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ fd_exec_instr_ctx_t const * ctx ) { ulong i = 0; - ulong j = deq_fd_slot_hash_t_cnt( slot_hashes->hashes ); + ulong j = deq_fd_slot_hash_t_cnt( slot_hashes ); ulong vote_slots_len = deq_ulong_cnt( vote_slots ); // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L462 @@ -1154,8 +1151,8 @@ check_slots_are_valid( fd_vote_state_t * vote_state, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L476 if( FD_UNLIKELY( *deq_ulong_peek_index_const( vote_slots, i ) != - deq_fd_slot_hash_t_peek_index( slot_hashes->hashes, - fd_ulong_checked_sub_expect( j, 1, "`j` is positive" ) ) + deq_fd_slot_hash_t_peek_index_const( slot_hashes, + fd_ulong_checked_sub_expect( j, 1, "`j` is positive" ) ) ->slot ) ) { j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when finding newer slots" ); continue; @@ -1168,7 +1165,7 @@ check_slots_are_valid( fd_vote_state_t * vote_state, } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L494 - if( FD_UNLIKELY( j == deq_fd_slot_hash_t_cnt( slot_hashes->hashes ) ) ) { + if( FD_UNLIKELY( j == deq_fd_slot_hash_t_cnt( slot_hashes ) ) ) { ctx->txn_ctx->custom_err = FD_VOTE_ERROR_VOTE_TOO_OLD; return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; } @@ -1177,7 +1174,7 @@ check_slots_are_valid( fd_vote_state_t * vote_state, return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L514 - if( FD_UNLIKELY( 0 != memcmp( &deq_fd_slot_hash_t_peek_index( slot_hashes->hashes, j )->hash, + if( FD_UNLIKELY( 0 != memcmp( &deq_fd_slot_hash_t_peek_index_const( slot_hashes, j )->hash, vote_hash, 32UL ) ) ) { ctx->txn_ctx->custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH; @@ -1679,7 +1676,7 @@ static int process_vote_unfiltered( fd_vote_state_t * vote_state, ulong * vote_slots, fd_vote_t const * vote, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ ulong epoch, ulong current_slot, fd_exec_instr_ctx_t const * ctx ) { @@ -1701,7 +1698,7 @@ process_vote_unfiltered( fd_vote_state_t * vote_state, static int process_vote( fd_vote_state_t * vote_state, fd_vote_t const * vote, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ ulong epoch, ulong current_slot, fd_exec_instr_ctx_t const * ctx ) { @@ -1713,8 +1710,8 @@ process_vote( fd_vote_state_t * vote_state, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L795 ulong earliest_slot_in_history = 0; - if( FD_UNLIKELY( !deq_fd_slot_hash_t_empty( slot_hashes->hashes ) ) ) { - earliest_slot_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes->hashes )->slot; + if( FD_UNLIKELY( !deq_fd_slot_hash_t_empty( slot_hashes ) ) ) { + earliest_slot_in_history = deq_fd_slot_hash_t_peek_tail_const( slot_hashes )->slot; } ulong vote_slots_cnt = deq_ulong_cnt( vote->slots ); @@ -1826,7 +1823,7 @@ verify_and_get_vote_state( fd_borrowed_account_t * vote_account, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1104 static int process_vote_with_account( fd_borrowed_account_t * vote_account, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ fd_sol_sysvar_clock_t const * clock, fd_vote_t * vote, fd_pubkey_t const * signers[static FD_TXN_SIG_MAX], @@ -1874,7 +1871,7 @@ process_vote_with_account( fd_borrowed_account_t * vote_account, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1156 static int do_process_vote_state_update( fd_vote_state_t * vote_state, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ ulong epoch, ulong slot, fd_vote_state_update_t * vote_state_update, @@ -1936,7 +1933,7 @@ fd_query_pubkey_stake( fd_pubkey_t const * pubkey, fd_vote_accounts_global_t con static int process_vote_state_update( fd_borrowed_account_t * vote_account, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, fd_sol_sysvar_clock_t const * clock, fd_vote_state_update_t * vote_state_update, fd_pubkey_t const * signers[static FD_TXN_SIG_MAX], @@ -1996,7 +1993,7 @@ process_vote_state_update( fd_borrowed_account_t * vote_account, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1206 static int do_process_tower_sync( fd_vote_state_t * vote_state, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ ulong epoch, ulong slot, fd_tower_sync_t * tower_sync, @@ -2032,7 +2029,7 @@ do_process_tower_sync( fd_vote_state_t * vote_state, // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1186 static int process_tower_sync( fd_borrowed_account_t * vote_account, - fd_slot_hashes_t const * slot_hashes, + fd_slot_hash_t const * slot_hashes, /* deque */ fd_sol_sysvar_clock_t const * clock, fd_tower_sync_t * tower_sync, fd_pubkey_t const * signers[static FD_TXN_SIG_MAX], @@ -2173,7 +2170,8 @@ fd_vote_acc_credits( fd_exec_instr_ctx_t const * ctx, ulong * result ) { int rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; /* Read vote account */ @@ -2275,7 +2273,9 @@ process_authorize_with_seed_instruction( // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L31 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; fd_pubkey_t * expected_authority_keys[FD_TXN_SIG_MAX] = { 0 }; @@ -2395,7 +2395,8 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L72 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_rent_t const * rent = fd_sysvar_rent_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_rent_t rent_; + fd_rent_t const * rent = fd_sysvar_rent_read( ctx->sysvar_cache, &rent_ ); if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &me ) < @@ -2405,7 +2406,8 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L76 rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L78 @@ -2433,7 +2435,8 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L87 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L89 @@ -2546,11 +2549,14 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { case fd_vote_instruction_enum_update_commission: { // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L149 - fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_epoch_schedule_t epoch_schedule_; + fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( ctx->sysvar_cache, &epoch_schedule_ ); if( FD_UNLIKELY( !epoch_schedule ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L150 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; @@ -2602,21 +2608,20 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { err = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_slot_hashes_id ); if( FD_UNLIKELY( err ) ) return err; - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - fd_slot_hashes_t slot_hashes[1]; - if( FD_LIKELY( slot_hashes_global ) ) { - slot_hashes->hashes = deq_fd_slot_hash_t_join( (uchar*)slot_hashes_global + slot_hashes_global->hashes_offset ); - } else { + if( FD_UNLIKELY( !fd_sysvar_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L157 err = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id ); if( FD_UNLIKELY( err ) ) return err; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; + fd_slot_hash_t const * slot_hashes = fd_sysvar_slot_hashes_join_const( ctx->sysvar_cache ); /* guaranteed to succeed */ rc = process_vote_with_account( &me, slot_hashes, clock, vote, signers, ctx ); + fd_sysvar_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes ); break; } @@ -2657,21 +2662,20 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L171 - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - fd_slot_hashes_t slot_hashes[1]; - if( FD_LIKELY( slot_hashes_global ) ) { - slot_hashes->hashes = deq_fd_slot_hash_t_join( (uchar*)slot_hashes_global + slot_hashes_global->hashes_offset ); - } else { + if( FD_LIKELY( !fd_sysvar_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L172 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L173 + fd_slot_hash_t const * slot_hashes = fd_sysvar_slot_hashes_join_const( ctx->sysvar_cache ); rc = process_vote_state_update( &me, slot_hashes, clock, vote_state_update, signers, ctx ); + fd_sysvar_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes ); break; } @@ -2721,20 +2725,19 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L185 - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - fd_slot_hashes_t slot_hashes[1]; - if( FD_LIKELY( slot_hashes_global ) ) { - slot_hashes->hashes = deq_fd_slot_hash_t_join( (uchar*)slot_hashes_global + slot_hashes_global->hashes_offset ); - } else { + if( FD_LIKELY( !fd_sysvar_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L187 + fd_slot_hash_t const * slot_hashes = fd_sysvar_slot_hashes_join_const( ctx->sysvar_cache ); /* guaranteed to succeed */ rc = process_vote_state_update( &me, slot_hashes, clock, &vote_update, signers, ctx ); + fd_sysvar_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes ); break; } @@ -2754,18 +2757,20 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { ? &instruction->inner.tower_sync : &instruction->inner.tower_sync_switch.tower_sync; - fd_slot_hashes_global_t const * slot_hashes_global = fd_sysvar_slot_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - fd_slot_hashes_t slot_hashes[1]; - if( FD_LIKELY( slot_hashes_global ) ) { - slot_hashes->hashes = deq_fd_slot_hash_t_join( (uchar*)slot_hashes_global + slot_hashes_global->hashes_offset ); + if( FD_LIKELY( !fd_sysvar_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) { + return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !slot_hashes_global || !clock ) ) { + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); + if( FD_UNLIKELY( !clock ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } + fd_slot_hash_t const * slot_hashes = fd_sysvar_slot_hashes_join_const( ctx->sysvar_cache ); rc = process_tower_sync( &me, slot_hashes, clock, tower_sync, signers, ctx ); + fd_sysvar_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes ); + break; } @@ -2782,10 +2787,12 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { rc = FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS; break; } - fd_rent_t const * rent_sysvar = fd_sysvar_rent_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_rent_t rent_; + fd_rent_t const * rent_sysvar = fd_sysvar_rent_read( ctx->sysvar_cache, &rent_ ); if( FD_UNLIKELY( !rent_sysvar ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; - fd_sol_sysvar_clock_t const * clock_sysvar = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock_sysvar = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock_sysvar ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; @@ -2832,7 +2839,8 @@ fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) { // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L242 rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id ); if( FD_UNLIKELY( rc ) ) return rc; - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); + fd_sol_sysvar_clock_t clock_; + fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( ctx->sysvar_cache, &clock_ ); if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; rc = authorize( &me, diff --git a/src/flamenco/runtime/program/test_program_cache.c b/src/flamenco/runtime/program/test_program_cache.c index 7b39121d80..6699f51e05 100644 --- a/src/flamenco/runtime/program/test_program_cache.c +++ b/src/flamenco/runtime/program/test_program_cache.c @@ -226,7 +226,7 @@ test_program_in_cache_needs_reverification( void ) { FD_TEST( valid_prog->last_epoch_verification_ran==1UL ); /* Fast forward to next epoch */ - test_slot_ctx->bank->slot += 432000UL; + test_slot_ctx->bank->slot_ += 432000UL; /* This should trigger reverification */ fd_bpf_program_update_program_cache( test_slot_ctx, &test_program_pubkey, test_spad ); @@ -288,8 +288,8 @@ main( int argc, test_slot_ctx->funk = test_funk; /* Set up bank */ - ulong banks_footprint = fd_banks_footprint( 1UL ); - uchar * banks_mem = fd_wksp_alloc_laddr( test_wksp, fd_banks_align(), banks_footprint, TEST_WKSP_TAG ); + ulong banks_footprint = fd_banks_footprint( 1UL ); + uchar * banks_mem = fd_wksp_alloc_laddr( test_wksp, fd_banks_align(), banks_footprint, TEST_WKSP_TAG ); FD_TEST( banks_mem ); fd_banks_t * banks = fd_banks_join( fd_banks_new( banks_mem, 1UL ) ); @@ -300,14 +300,14 @@ main( int argc, test_slot_ctx->bank = bank; test_slot_ctx->banks = banks; - fd_epoch_schedule_t epoch_schedule = { + fd_epoch_schedule_t const epoch_schedule = { .slots_per_epoch = 432000UL, .leader_schedule_slot_offset = 432000UL, .warmup = 0, .first_normal_epoch = 0UL, .first_normal_slot = 0UL }; - fd_bank_epoch_schedule_set( bank, epoch_schedule ); + fd_sysvar_epoch_schedule_write( test_slot_ctx, &epoch_schedule ); test_account_does_not_exist(); test_account_not_bpf_loader_owner(); diff --git a/src/flamenco/runtime/sysvar/Local.mk b/src/flamenco/runtime/sysvar/Local.mk index 2059760ef9..303ccc622c 100644 --- a/src/flamenco/runtime/sysvar/Local.mk +++ b/src/flamenco/runtime/sysvar/Local.mk @@ -2,6 +2,9 @@ ifdef FD_HAS_INT128 $(call add-hdrs,fd_sysvar.h) $(call add-objs,fd_sysvar,fd_flamenco) +$(call add-hdrs,fd_sysvar_cache.h) +$(call add-objs,fd_sysvar_cache,fd_flamenco) + $(call add-hdrs,fd_sysvar_clock.h) $(call add-objs,fd_sysvar_clock,fd_flamenco) @@ -10,10 +13,6 @@ $(call add-objs,fd_sysvar_epoch_rewards,fd_flamenco) $(call add-hdrs,fd_sysvar_epoch_schedule.h) $(call add-objs,fd_sysvar_epoch_schedule,fd_flamenco) -ifdef FD_HAS_HOSTED -$(call make-unit-test,test_sysvar_epoch_schedule,test_sysvar_epoch_schedule,fd_flamenco fd_funk fd_ballet fd_util) -$(call run-unit-test,test_sysvar_epoch_schedule) -endif $(call add-hdrs,fd_sysvar_instructions.h) $(call add-objs,fd_sysvar_instructions,fd_flamenco) @@ -25,11 +24,7 @@ $(call add-hdrs,fd_sysvar_recent_hashes.h) $(call add-objs,fd_sysvar_recent_hashes,fd_flamenco) $(call add-hdrs,fd_sysvar_rent.h) -$(call add-objs,fd_sysvar_rent fd_sysvar_rent1,fd_flamenco) -ifdef FD_HAS_HOSTED -$(call make-unit-test,test_sysvar_rent,test_sysvar_rent,fd_flamenco fd_ballet fd_util) -$(call run-unit-test,test_sysvar_rent) -endif +$(call add-objs,fd_sysvar_rent,fd_flamenco) $(call add-hdrs,fd_sysvar_slot_hashes.h) $(call add-objs,fd_sysvar_slot_hashes,fd_flamenco) @@ -39,4 +34,9 @@ $(call add-objs,fd_sysvar_slot_history,fd_flamenco) $(call add-hdrs,fd_sysvar_stake_history.h) $(call add-objs,fd_sysvar_stake_history,fd_flamenco) + +ifdef FD_HAS_HOSTED +$(call make-unit-test,test_sysvar,test_sysvar,fd_flamenco fd_funk fd_ballet fd_util) +$(call run-unit-test,test_sysvar) +endif endif diff --git a/src/flamenco/runtime/sysvar/fd_sysvar.c b/src/flamenco/runtime/sysvar/fd_sysvar.c index c67950d083..a2999e30ad 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar.c @@ -1,54 +1,8 @@ #include "fd_sysvar.h" -#include "../context/fd_exec_slot_ctx.h" #include "../context/fd_exec_instr_ctx.h" #include "../context/fd_exec_txn_ctx.h" -#include "fd_sysvar_rent.h" - -/* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank.rs#L1813 */ -int -fd_sysvar_set( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_pubkey_t const * owner, - fd_pubkey_t const * pubkey, - void const * data, - ulong sz, - ulong slot ) { - - FD_TXN_ACCOUNT_DECL( rec ); - - int err = fd_txn_account_init_from_funk_mutable( rec, pubkey, funk, funk_txn, 1, sz ); - if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) - return FD_ACC_MGR_ERR_READ_FAILED; - - fd_memcpy(rec->vt->get_data_mut( rec ), data, sz); - - /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank.rs#L1825 */ - fd_acc_lamports_t lamports_before = rec->vt->get_lamports( rec ); - /* https://github.com/anza-xyz/agave/blob/ae18213c19ea5335dfc75e6b6116def0f0910aff/runtime/src/bank.rs#L6184 - The account passed in via the updater is always the current sysvar account, so we take the max of the - current account lamports and the minimum rent exempt balance needed. */ - fd_rent_t const * rent = fd_bank_rent_query( bank ); - fd_acc_lamports_t lamports_after = fd_ulong_max( lamports_before, fd_rent_exempt_minimum_balance( rent, sz ) ); - rec->vt->set_lamports( rec, lamports_after ); - - /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank.rs#L1826 */ - if( lamports_after > lamports_before ) { - fd_bank_capitalization_set( bank, fd_bank_capitalization_get( bank ) + (lamports_after - lamports_before) ); - } else if( lamports_after < lamports_before ) { - fd_bank_capitalization_set( bank, fd_bank_capitalization_get( bank ) - (lamports_before - lamports_after) ); - } - - rec->vt->set_data_len( rec, sz ); - rec->vt->set_owner( rec, owner ); - rec->vt->set_slot( rec, slot ); - - fd_txn_account_mutable_fini( rec, funk, funk_txn ); - return 0; -} - -int +FD_FN_PURE int fd_sysvar_instr_acct_check( fd_exec_instr_ctx_t const * ctx, ulong idx, fd_pubkey_t const * addr_want ) { diff --git a/src/flamenco/runtime/sysvar/fd_sysvar.h b/src/flamenco/runtime/sysvar/fd_sysvar.h index 2fe3bb25b2..5ec960d2e4 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar.h @@ -1,26 +1,18 @@ #ifndef HEADER_fd_src_flamenco_runtime_fd_sysvar_h #define HEADER_fd_src_flamenco_runtime_fd_sysvar_h -#include "../fd_bank.h" -#include "../../fd_flamenco_base.h" -#include "../../../funk/fd_funk.h" +#include "../../types/fd_types_custom.h" /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank.rs#L1833 */ #define FD_SYSVAR_RENT_UNADJUSTED_INITIAL_BALANCE ( 1UL ) /* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank.rs#L1843 */ #define FD_SYSVAR_INITIAL_RENT_EPOCH ( 0UL ) -int -fd_sysvar_set( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_pubkey_t const * owner, - fd_pubkey_t const * pubkey, - void const * data, - ulong sz, - ulong slot ); +/* fd_sysvar_instr_acct_check checks whether the provided instruction + account index is the sysvar at the given address. Returns one of + FD_EXECUTOR_INSTR_{ERR_*,SUCCESS}. */ -int +FD_FN_PURE int fd_sysvar_instr_acct_check( fd_exec_instr_ctx_t const * ctx, ulong idx, fd_pubkey_t const * addr_want ); diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache.c b/src/flamenco/runtime/sysvar/fd_sysvar_cache.c new file mode 100644 index 0000000000..a22e33ba6b --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache.c @@ -0,0 +1,240 @@ +#include "fd_sysvar_cache.h" +#include "fd_sysvar_cache_private.h" +#include "fd_sysvar.h" +#include "../context/fd_exec_slot_ctx.h" +#include "../fd_system_ids_pp.h" +#include "fd_sysvar_clock.h" + +struct sysvar_tbl { + fd_pubkey_t key; + uchar desc_idx; +}; +typedef struct sysvar_tbl sysvar_tbl_t; + +#define MAP_PERFECT_NAME sysvar_map +#define MAP_PERFECT_LG_TBL_SZ 4 +#define MAP_PERFECT_T sysvar_tbl_t +#define MAP_PERFECT_HASH_C 212885 +#define MAP_PERFECT_KEY key.uc +#define MAP_PERFECT_KEY_T fd_pubkey_t const * +#define MAP_PERFECT_ZERO_KEY (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0) +#define MAP_PERFECT_COMPLEX_KEY 1 +#define MAP_PERFECT_KEYS_EQUAL(k1,k2) (!memcmp( (k1), (k2), 32UL )) +#define PERFECT_HASH( u ) (((MAP_PERFECT_HASH_C*(u))>>28)&0xFU) +#define MAP_PERFECT_HASH_PP( a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \ + a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \ + PERFECT_HASH( (a08 | (a09<<8) | (a10<<16) | (a11<<24)) ) +#define MAP_PERFECT_HASH_R( ptr ) PERFECT_HASH( fd_uint_load_4( (uchar const *)ptr + 8UL ) ) +#define MAP_SYSVAR( id, desc ) ( id ), .desc_idx = ( offsetof( fd_sysvar_cache_descs_t, desc ) / sizeof(fd_sysvar_cache_desc_t) ) +#define MAP_PERFECT_0 MAP_SYSVAR( SYSVAR_CLOCK_ID, clock ) +#define MAP_PERFECT_1 MAP_SYSVAR( SYSVAR_SLOT_HIST_ID, slot_history ) +#define MAP_PERFECT_2 MAP_SYSVAR( SYSVAR_SLOT_HASHES_ID, slot_hashes ) +#define MAP_PERFECT_3 MAP_SYSVAR( SYSVAR_EPOCH_SCHED_ID, epoch_schedule ) +#define MAP_PERFECT_4 MAP_SYSVAR( SYSVAR_RECENT_BLKHASH_ID, recent_block_hashes ) +#define MAP_PERFECT_5 MAP_SYSVAR( SYSVAR_RENT_ID, rent ) +#define MAP_PERFECT_6 MAP_SYSVAR( SYSVAR_EPOCH_REWARDS_ID, epoch_rewards ) +#define MAP_PERFECT_7 MAP_SYSVAR( SYSVAR_STAKE_HIST_ID, stake_history ) +#define MAP_PERFECT_8 MAP_SYSVAR( SYSVAR_LAST_RESTART_ID, last_restart_slot ) +#include "../../../util/tmpl/fd_map_perfect.c" +#undef PERFECT_HASH + +FD_FN_CONST ulong +fd_sysvar_cache_align( void ) { + return FD_SYSVAR_CACHE_ALIGN; +} + +FD_FN_CONST ulong +fd_sysvar_cache_footprint( void ) { + return FD_SYSVAR_CACHE_FOOTPRINT; +} + +void * +fd_sysvar_cache_new( void * mem ) { + + if( FD_UNLIKELY( !mem ) ) { + FD_LOG_WARNING(( "NULL mem" )); + return NULL; + } + if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_SYSVAR_CACHE_ALIGN ) ) ) { + FD_LOG_WARNING(( "misaligned mem" )); + return NULL; + } + + memset( mem, 0, sizeof(fd_sysvar_cache_footprint()) ); + fd_sysvar_cache_t * sysvar_cache = mem; + + FD_COMPILER_MFENCE(); + sysvar_cache->magic = FD_SYSVAR_CACHE_MAGIC; + FD_COMPILER_MFENCE(); + + return sysvar_cache; +} + +fd_sysvar_cache_t * +fd_sysvar_cache_join( void * mem ) { + /* FIXME refcount writer */ + return (fd_sysvar_cache_t *)fd_sysvar_cache_join_const( mem ); +} + +fd_sysvar_cache_t const * +fd_sysvar_cache_join_const( void const * mem ) { + + if( FD_UNLIKELY( !mem ) ) { + FD_LOG_WARNING(( "NULL mem" )); + return NULL; + } + if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_SYSVAR_CACHE_ALIGN ) ) ) { + FD_LOG_WARNING(( "misaligned mem" )); + return NULL; + } + fd_sysvar_cache_t const * sysvar_cache = mem; + if( FD_UNLIKELY( sysvar_cache->magic != FD_SYSVAR_CACHE_MAGIC ) ) { + FD_LOG_WARNING(( "bad magic" )); + return NULL; + } + + return sysvar_cache; +} + +void * +fd_sysvar_cache_leave( fd_sysvar_cache_t * sysvar_cache ) { + return sysvar_cache; +} + +void const * +fd_sysvar_cache_leave_const( fd_sysvar_cache_t const * sysvar_cache ) { + return sysvar_cache; +} + +void * +fd_sysvar_cache_delete( void * mem ) { + + if( FD_UNLIKELY( !mem ) ) { + FD_LOG_WARNING(( "NULL mem" )); + return NULL; + } + fd_sysvar_cache_t * sysvar_cache = mem; + if( FD_UNLIKELY( sysvar_cache->magic != FD_SYSVAR_CACHE_MAGIC ) ) { + FD_LOG_WARNING(( "bad magic" )); + return NULL; + } + + memset( sysvar_cache, 0, sizeof(fd_sysvar_cache_t) ); + + return mem; +} + +void * +fd_sysvar_cache_clone( void * mem2, + fd_sysvar_cache_t const * orig ) { + + if( FD_UNLIKELY( !mem2 ) ) { + FD_LOG_WARNING(( "NULL mem2" )); + return NULL; + } + if( FD_UNLIKELY( !orig ) ) { + FD_LOG_WARNING(( "NULL orig" )); + return NULL; + } + if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem2, FD_SYSVAR_CACHE_ALIGN ) ) ) { + FD_LOG_WARNING(( "misaligned mem" )); + return NULL; + } + if( FD_UNLIKELY( orig->magic!=FD_SYSVAR_CACHE_MAGIC ) ) { + FD_LOG_WARNING(( "bad magic" )); + return NULL; + } + + memcpy( mem2, orig, fd_sysvar_cache_footprint() ); + return mem2; +} + +void +fd_sysvar_cache_recover( fd_exec_slot_ctx_t * slot_ctx ) { + +} + +uchar const * +fd_sysvar_cache_data_query( + fd_sysvar_cache_t const * sysvar_cache, + void const * address, /* 32 bytes */ + ulong * psz +) { + fd_pubkey_t pubkey; memcpy( pubkey.uc, address, 32UL ); + sysvar_tbl_t const * entry = sysvar_map_query( &pubkey, NULL ); + if( FD_UNLIKELY( !entry ) ) return NULL; /* address is not a sysvar */ + fd_sysvar_cache_desc_t const * desc = &sysvar_cache->desc_tbl[ entry->desc_idx ]; + if( !fd_sysvar_cache_flags_valid( desc->flags ) ) return NULL; /* sysvar data invalid */ + *psz = desc->data_sz; + return (uchar const *)fd_sysvar_cache_data_laddr( sysvar_cache, desc ); +} + +uchar * +fd_sysvar_cache_data_modify_prepare( + fd_exec_slot_ctx_t * slot_ctx, + void const * address, /* 32 bytes */ + ulong * opt_sz, + ulong * opt_sz_max +) { + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + fd_pubkey_t pubkey; memcpy( pubkey.uc, address, 32UL ); + sysvar_tbl_t const * entry = sysvar_map_query( &pubkey, NULL ); + if( FD_UNLIKELY( !entry ) ) { + char address_cstr[ FD_BASE58_ENCODED_32_SZ ]; + fd_base58_encode_32( address, NULL, address_cstr ); + FD_LOG_ERR(( "fd_sysvar_cache_data_modify_prepare: %s is not a supported sysvar", + address_cstr )); + } + fd_sysvar_cache_desc_t * desc = &cache->desc_tbl[ entry->desc_idx ]; + /* FIXME clear the valid bit */ + *opt_sz = desc->data_sz; + *opt_sz_max = desc->data_sz_max; +} + +void +fd_sysvar_cache_data_modify_commit( + fd_exec_slot_ctx_t * slot_ctx, + void const * address, /* 32 bytes */ + ulong sz +) { + /* FIXME write lock */ +} + +fd_sol_sysvar_clock_t * +fd_sysvar_clock_read( fd_sysvar_cache_t const * cache, + fd_sol_sysvar_clock_t * clock ) { + fd_sysvar_cache_desc_t const * desc = &cache->desc.clock; + if( FD_UNLIKELY( !desc->obj_off ) ) return NULL; + return memcpy( clock, (uchar *)cache+desc->obj_off, sizeof(fd_sol_sysvar_clock_t) ); +} + +void +fd_sysvar_clock_write( + fd_exec_slot_ctx_t * slot_ctx, + fd_sol_sysvar_clock_t const * clock +) { + fd_sysvar_cache_t * cache = slot_ctx->sysvar_cache; + fd_sysvar_cache_desc_t * desc = &cache->desc.clock; + fd_sysvar_cache_desc_write_lock( desc ); + + uchar * buf = (uchar *)fd_sysvar_cache_data_laddr( cache, desc ); + ulong buf_max = FD_SYSVAR_CLOCK_BINCODE_SZ; + + fd_bincode_encode_ctx_t encode_ctx = { + .data = buf, + .dataend = buf+buf_max, + }; + fd_sol_sysvar_clock_encode( clock, &encode_ctx ); + + fd_sysvar_cache_desc_write_unlock( desc ); +} + +fd_slot_hash_t * +fd_sysvar_slot_hashes_join( + fd_sysvar_cache_t * sysvar_cache +); + +fd_slot_hash_t const * +fd_sysvar_slot_hashes_join_const( + fd_sysvar_cache_t const * sysvar_cache +); diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache.h b/src/flamenco/runtime/sysvar/fd_sysvar_cache.h new file mode 100644 index 0000000000..98b8670070 --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache.h @@ -0,0 +1,444 @@ +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h + +/* fd_sysvar_cache.h is the main API to read and write sysvar accounts + and data structures. All runtime sysvar accesses should use this API + (except snapshot loading). + + See /doc/runtime/sysvars.md for different types of sysvars and their + write and cache invalidation behavior. (TLDR This is a write-through + cache of sysvar account data) */ + +#include "../../types/fd_types.h" + +/* FD_SYSVAR_CACHE_{ALIGN,FOOTPRINT} specify the static requirements for + a memory region suitable of holding a sysvar_cache object. */ + +#define FD_SYSVAR_CACHE_ALIGN (16UL) +#define FD_SYSVAR_CACHE_FOOTPRINT (50000UL) /* TODO */ + +#define FD_SYSVAR_CACHE_MAGIC (0x1aa5ecb2a49b600aUL) /* random number */ + +/* fd_sysvar_cache_t is the header of a sysvar_cache object. + A sysvar_cache object is position-independent and backed entirely by + a single memory region. Each sysvar is stored in serialized/raw form + and in a typed form, see fd_sysvar_cache_desc_t. + + Should not be declared locally (allocate via align/footprint/new). + Use accessor APIs instead of using struct members directly. + + It is safe to relocate a sysvar_cache object, or map it from multiple + processes with different address spaces, or clone it via a shallow + memcpy (see fd_sysvar_cache_clone). + + Concurrently, the APIs below don't support concurrent access (atomics + are used to detect concurrent access and force a crash). The caller + should use external synchronization to coordinate reads and writes + from different threads. */ + +struct fd_sysvar_cache_desc { + /* Offsets relative to start of sysvar cache */ + uint data_off; /* Raw data offset */ + uint data_sz; /* Raw data size */ + uint obj_off; /* Typed object offset */ + uint flags; +}; +typedef struct fd_sysvar_cache_desc fd_sysvar_cache_desc_t; + +struct fd_sysvar_cache_descs { + fd_sysvar_cache_desc_t clock; + fd_sysvar_cache_desc_t epoch_rewards; + fd_sysvar_cache_desc_t epoch_schedule; + fd_sysvar_cache_desc_t last_restart_slot; + fd_sysvar_cache_desc_t recent_block_hashes; + fd_sysvar_cache_desc_t rent; + fd_sysvar_cache_desc_t slot_hashes; + fd_sysvar_cache_desc_t slot_history; + fd_sysvar_cache_desc_t stake_history; + /* Note the "fees" sysvar is no longer relevant */ +}; +typedef struct fd_sysvar_cache_descs fd_sysvar_cache_descs_t; + +struct fd_sysvar_cache { + ulong magic; /* ==FD_SYSVAR_CACHE_MAGIC */ + + union { + fd_sysvar_cache_descs_t desc; + fd_sysvar_cache_desc_t desc_tbl[ 9 ]; + }; +}; + +typedef struct fd_sysvar_cache fd_sysvar_cache_t; + +FD_PROTOTYPES_BEGIN + +/* Constructor API */ + +/* fd_sysvar_cache_{align,footprint} return + FD_SYSVAR_CACHE_{ALIGN,FOOTPRINT}. */ + +FD_FN_CONST ulong +fd_sysvar_cache_align( void ); + +FD_FN_CONST ulong +fd_sysvar_cache_footprint( void ); + +/* fd_sysvar_cache_new formats a memory region allocated according to + fd_sysvar_cache_{align,footprint} for use as a sysvar_cache object. */ + +void * +fd_sysvar_cache_new( void * mem ); + +/* fd_sysvar_cache_join joins the caller to a sysvar_cache object as + writable mode. fd_sysvar_cache_join_const is the read-only version. */ + +fd_sysvar_cache_t * +fd_sysvar_cache_join( void * mem ); + +fd_sysvar_cache_t const * +fd_sysvar_cache_join_const( void const * mem ); + +/* fd_sysvar_cache_leave undoes a join to a sysvar_cache object. */ + +void * +fd_sysvar_cache_leave( fd_sysvar_cache_t * sysvar_cache ); + +void const * +fd_sysvar_cache_leave_const( fd_sysvar_cache_t const * sysvar_cache ); + +/* fd_sysvar_cache_delete releases the sysvar cache object's backing + memory region back to the caller. */ + +void * +fd_sysvar_cache_delete( void * mem ); + +/* fd_sysvar_cache_clone clones a sysvar cache object from a join in + orig to a new memory region to mem2. */ + +void * +fd_sysvar_cache_clone( void * mem2, + fd_sysvar_cache_t const * orig ); + +/* fd_sysvar_cache_recover rebuilds the sysvar cache from the account + database. Logs warnings in case sysvar datas fail to deserialize. + FIXME consider taking a database handle instead of slot_ctx */ + +void +fd_sysvar_cache_recover( fd_exec_slot_ctx_t * slot_ctx ); + +/* Generic accessors for serialized sysvar account data. */ + +/* fd_sysvar_cache_data_query returns a pointer to raw/serialized sysvar + account data. address points to the address of the sysvar account. + *psz is set to the serialized data size (or 0 on failure). + The returned pointer is valid until the next API call that takes a + non-const pointer to sysvar_cache. Note there are technically three + outcomes (retval is the return value): + - retval!=NULL && *psz!=0 sysvar is valid + - retval==NULL && *psz==0 no sysvar with this address or sysvar + or sysvar contains invalid data + - retval!=NULL && *psz==0 sysvar is valid, but empty (impossible + with current sysvars) */ + +uchar const * +fd_sysvar_cache_data_query( + fd_sysvar_cache_t const * sysvar_cache, + void const * address, /* 32 bytes */ + ulong * psz +); + +/* fd_sysvar_cache_data_modify_{prepare,commit} allow writing raw sysvar + data. + + fd_sysvar_cache_data_modify_prepare prepares a sysvar data buffer + for writing. If opt_sz!=NULL, then *opt_sz is set to the current + sysvar size. If opt_sz_max!=NULL, then *opt_sz_max is set to the max + size that may be written. The caller writes the sysvar data to the + returned pointer. The returned pointer is valid if the given address + matches a cacheable sysvar account. Otherwise, it is NULL. + + fd_sysvar_cache_data_modify_commit marks the end of a raw sysvar data + write. Persists the write down to the database, and updates the + cache itself (recovers a typed representation from the write). + Crashes the app with FD_LOG_ERR if the write fails (e.g. database out + of space, disk disappeared, ...). */ + +uchar * +fd_sysvar_cache_data_modify_prepare( + fd_exec_slot_ctx_t * slot_ctx, + void const * address, /* 32 bytes */ + ulong * opt_sz, + ulong * opt_sz_max +); + +void +fd_sysvar_cache_data_modify_commit( + fd_exec_slot_ctx_t * slot_ctx, + void const * address, /* 32 bytes */ + ulong sz +); + +/* fd_sysvar_cache_flags_valid returns 1 if there is a valid typed + object for a sysvar cache entry, otherwise returns 0. */ + +static inline uint +fd_sysvar_cache_flags_valid( uint flags ) { + return flags & 1; +} + +uint +fd_sysvar_cache_flags_exists( uint flags ); + +#define FD_SYSVAR_CACHE_EXISTS( sysvar_cache, sysvar ) \ + ( fd_sysvar_cache_flags_exists( sysvar_cache->desc.sysvar.flags ) ) + +/* Accessors for small POD sysvars. These do a copy on read and write. + + fd_sysvar_clock_is_valid returns 1 if the cached sysvar is valid + (read, read_nofail, join are then guaranteed to succeed). Returns 0 + otherwise. + + fd_sysvar_clock_read attempts to copy sysvar data from cache into the + out argument. Returns out on success, or NULL if the sysvar account + does not exist or contains data that failed deserialization. + + fd_sysvar_clock_read_nofail returns a copy of the sysvar data. If + the sysvar does not exist or failed to deserialize, aborts the app + with FD_LOG_ERR. + + fd_sysvar_clock_write serializes sysvar data, updates the cache, and + does a blocking write to the account database. The sysvar account's + owner and lamport balance is changed if necessary (updates the bank's + capitalization). Writes to sysvars managed by this cache are only + allowed outside of transaction execution. + + Accessors for the other sysvars in this section are analogous. */ + +static inline int +fd_sysvar_clock_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.clock.flags ); +} + +fd_sol_sysvar_clock_t * +fd_sysvar_clock_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_sol_sysvar_clock_t * out +); + +fd_sol_sysvar_clock_t +fd_sysvar_clock_read_nofail( + fd_sysvar_cache_t const * sysvar_cache +); + +void +fd_sysvar_clock_write( + fd_exec_slot_ctx_t * slot_ctx, + fd_sol_sysvar_clock_t const * clock +); + +static inline int +fd_sysvar_epoch_rewards_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.epoch_rewards.flags ); +} + +fd_sysvar_epoch_rewards_t * +fd_sysvar_epoch_rewards_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_sysvar_epoch_rewards_t * out +); + +void +fd_sysvar_epoch_rewards_write( + fd_exec_slot_ctx_t * slot_ctx, + fd_sysvar_epoch_rewards_t const * epoch_rewards +); + +static inline int +fd_sysvar_epoch_schedule_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.epoch_schedule.flags ); +} + +fd_epoch_schedule_t * +fd_sysvar_epoch_schedule_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_epoch_schedule_t * out +); + +fd_epoch_schedule_t +fd_sysvar_epoch_schedule_read_nofail( fd_sysvar_cache_t const * sysvar_cache ); + +void +fd_sysvar_epoch_schedule_write( + fd_exec_slot_ctx_t * slot_ctx, + fd_epoch_schedule_t const * epoch_schedule +); + +static inline int +fd_sysvar_last_restart_slot_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.last_restart_slot.flags ); +} + +fd_sol_sysvar_last_restart_slot_t * +fd_sysvar_last_restart_slot_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_sol_sysvar_last_restart_slot_t * out +); + +void +fd_sysvar_last_restart_slot_write( + fd_exec_slot_ctx_t * slot_ctx, + fd_sol_sysvar_last_restart_slot_t const * last_restart_slot +); + +static inline int +fd_sysvar_rent_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.rent.flags ); +} + +fd_rent_t * +fd_sysvar_rent_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_rent_t * out +); + +fd_rent_t +fd_sysvar_rent_read_nofail( fd_sysvar_cache_t const * sysvar_cache ); + +void +fd_sysvar_rent_write( + fd_exec_slot_ctx_t * slot_ctx, + fd_rent_t const * rent +); + +/* Accessors for large sysvars. Each large sysvar has a join/leave + style API that provides thread-safe refcounted access to sysvars. + If a refcount is violated (e.g. attempt to const join a sysvar with + an active writable join), the process is terminated with FD_LOG_CRIT + (usually produces a core dump). */ + +static inline int +fd_sysvar_recent_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.recent_block_hashes.flags ); +} + +fd_block_block_hash_entry_t * /* deque */ +fd_sysvar_recent_hashes_join( + fd_exec_slot_ctx_t * slot_ctx +); + +fd_block_block_hash_entry_t const * /* deque */ +fd_sysvar_recent_hashes_join_const( + fd_sysvar_cache_t const * sysvar_cache +); + +void +fd_sysvar_recent_hashes_leave( + fd_sysvar_cache_t * sysvar_cache, + fd_block_block_hash_entry_t * hashes_deque +); + +void +fd_sysvar_recent_hashes_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_block_block_hash_entry_t const * hashes_deque +); + +/* fd_sysvar_slot_hashes_{join,leave}(_const) {attach,detach} the caller + {from,to} the slot hashes deque contained in the slot hashes sysvar. + + The join API returns a pointer into the sysvar cache. If the sysvar + account is in an invalid state (non-existent, failed to deserialize), + join returns NULL. */ + +static inline int +fd_sysvar_slot_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.slot_hashes.flags ); +} + +fd_slot_hash_t * +fd_sysvar_slot_hashes_join( + fd_sysvar_cache_t * sysvar_cache +); + +fd_slot_hash_t const * +fd_sysvar_slot_hashes_join_const( + fd_sysvar_cache_t const * sysvar_cache +); + +void +fd_sysvar_slot_hashes_leave( + fd_sysvar_cache_t * sysvar_cache, + fd_slot_hash_t * slot_hashes +); + +void +fd_sysvar_slot_hashes_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_slot_hash_t const * slot_hashes +); + +/* fd_sysvar_slot_history_{join,leave}(_const) {attach,detach} the + caller {from,to} the "slot history" sysvar. Behavior analogous to + above accessors. */ + +static inline int +fd_sysvar_slot_history_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.slot_history.flags ); +} + +fd_slot_history_global_t * +fd_sysvar_slot_history_join( + fd_sysvar_cache_t * sysvar_cache +); + +fd_slot_history_global_t const * +fd_sysvar_slot_history_join_const( + fd_sysvar_cache_t const * sysvar_cache +); + +void +fd_sysvar_slot_history_leave( + fd_sysvar_cache_t * sysvar_cache, + fd_slot_history_global_t * slot_history +); + +void +fd_sysvar_slot_history_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_slot_history_global_t const * slot_history +); + +/* fd_sysvar_stake_history_{join,leave}(_const) {attach,detach} the + caller {from,to} the "stake history" sysvar. Behavior analogous to + above accessors. */ + +static inline int +fd_sysvar_stake_history_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { + return !!fd_sysvar_cache_flags_valid( sysvar_cache->desc.stake_history.flags ); +} + +fd_stake_history_t * +fd_sysvar_stake_history_join( + fd_sysvar_cache_t * sysvar_cache +); + +fd_stake_history_t const * +fd_sysvar_stake_history_join_const( + fd_sysvar_cache_t const * sysvar_cache +); + +void +fd_sysvar_stake_history_leave( + fd_sysvar_cache_t * sysvar_cache, + fd_stake_history_t * stake_history +); + +void +fd_sysvar_stake_history_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_stake_history_t const * stake_history +); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h b/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h new file mode 100644 index 0000000000..1a0979d981 --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h @@ -0,0 +1,145 @@ +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_private_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_private_h + +#include "fd_sysvar_cache.h" + +/* Locking ************************************************************/ + +/* fd_sysvar_cache_flags_writer_cnt returns 1 if the sysvar is currently + being written to (conflicting reads and writes not allowed at this + time). */ + +static inline uint +fd_sysvar_cache_flags_writer_cnt( uint flags ) { + return !!( flags & 2 ); +} + +/* fd_sysvar_cache_flags_reader_cnt returns the number of readers + currently holding a reference to the sysvar (writes not allowed until + this counter reaches zero). */ + +static inline uint +fd_sysvar_cache_flags_reader_cnt( uint flags ) { + return flags>>2; +} + +#define FD_SYSVAR_CACHE_READER_MAX (0x3fffffffU) + +/* fd_sysvar_cache_desc_write_{lock,unlock} {acquires,releases} a write + lock on a sysvar cache entry. */ + +static inline void +fd_sysvar_cache_desc_write_lock( fd_sysvar_cache_desc_t * desc ) { + for(;;) { + uint const state_old = FD_VOLATILE_CONST( desc->flags ); + if( FD_UNLIKELY( fd_sysvar_cache_flags_writer_cnt( state_old ) ) ) { + FD_LOG_CRIT(( "Data race or reentrancy on sysvar cache write lock, this is a bug" )); + } + uint const state_new = fd_uint_set_bit( state_old, 2 ); +#if FD_HAS_ATOMIC + if( FD_UNLIKELY( !FD_ATOMIC_CAS( &desc->flags, state_old, state_new ) ) ) { + FD_SPIN_PAUSE(); + continue; + } +#else + FD_VOLATILE( desc->flags ) = state_new; +#endif + break; + } +} + +static inline void +fd_sysvar_cache_desc_write_unlock( fd_sysvar_cache_desc_t * desc ) { + for(;;) { + uint const state_old = FD_VOLATILE_CONST( desc->flags ); + if( FD_UNLIKELY( !fd_sysvar_cache_flags_writer_cnt( state_old ) ) ) { + FD_LOG_CRIT(( "Unmatched write_unlock on sysvar cache, this is a bug" )); + } + uint const state_new = fd_uint_clear_bit( state_old, 2 ); +#if FD_HAS_ATOMIC + if( FD_UNLIKELY( !FD_ATOMIC_CAS( &desc->flags, state_old, state_new ) ) ) { + FD_SPIN_PAUSE(); + continue; + } +#else + FD_VOLATILE( desc->flags ) = state_new; +#endif + break; + } +} + +/* fd_sysvar_cache_desc_read_{lock,unlock} {acquires,releases} a read + lock on a sysvar cache entry. */ + +static inline void +fd_sysvar_cache_desc_read_lock( fd_sysvar_cache_desc_t * desc ) { + for(;;) { + uint const state_old = FD_VOLATILE_CONST( desc->flags ); + if( FD_UNLIKELY( fd_sysvar_cache_flags_reader_cnt( state_old )>=FD_SYSVAR_CACHE_READER_MAX ) ) { + FD_LOG_CRIT(( "Too many concurrent read locks on sysvar cache entry, this is a bug" )); + } + uint const state_new = ( (state_old>>2)+1U ) | (state_old&3U); +#if FD_HAS_ATOMIC + if( FD_UNLIKELY( !FD_ATOMIC_CAS( &desc->flags, state_old, state_new ) ) ) { + FD_SPIN_PAUSE(); + continue; + } +#else + FD_VOLATILE( desc->flags ) = state_new; +#endif + break; + } +} + +static inline void +fd_sysvar_cache_desc_read_unlock( fd_sysvar_cache_desc_t * desc ) { + for(;;) { + uint const state_old = FD_VOLATILE_CONST( desc->flags ); + if( FD_UNLIKELY( !fd_sysvar_cache_flags_reader_cnt( state_old ) ) ) { + FD_LOG_CRIT(( "Unmatched read_unlock on sysvar cache, this is a bug" )); + } + uint const state_new = ( (state_old>>2)-1U ) | (state_old&3U); +#if FD_HAS_ATOMIC + if( FD_UNLIKELY( !FD_ATOMIC_CAS( &desc->flags, state_old, state_new ) ) ) { + FD_SPIN_PAUSE(); + continue; + } +#else + FD_VOLATILE( desc->flags ) = state_new; +#endif + break; + } +} + +/* Accessors **********************************************************/ + +ulong +fd_sysvar_cache_data_laddr( fd_sysvar_cache_t const * sysvar_cache, + fd_sysvar_cache_desc_t const * desc ) { + if( FD_UNLIKELY( !desc->data_off ) ) FD_LOG_CRIT(( "zero sysvar_cache_desc data_off" )); + return (ulong)sysvar_cache + desc->data_off; +} + +ulong +fd_sysvar_cache_obj_laddr( fd_sysvar_cache_t const * sysvar_cache, + fd_sysvar_cache_desc_t const * desc ) { + if( FD_UNLIKELY( !desc->obj_off ) ) FD_LOG_CRIT(( "zero sysvar_cache_desc obj_off" )); + return (ulong)sysvar_cache + desc->obj_off; +} + +/* Database ***********************************************************/ + +/* fd_sysvar_account_update persists a sysvar data update to the account + database. + + THIS API SHOULD NEVER BE USED DIRECTLY. All runtime writes should + use sysvar cache APIs, snapshot restore should use + fd_sysvar_cache_recover. */ + +void +fd_sysvar_account_update( fd_exec_slot_ctx_t * slot_ctx, + fd_pubkey_t const * address, + void const * data, + ulong sz ); + +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_private_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_clock.c b/src/flamenco/runtime/sysvar/fd_sysvar_clock.c index bf7ddaa752..4274c9fd8d 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_clock.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_clock.c @@ -1,10 +1,6 @@ +#include "fd_sysvar_cache.h" #include "fd_sysvar_clock.h" #include "fd_sysvar_epoch_schedule.h" -#include "fd_sysvar_rent.h" -#include "../fd_executor.h" -#include "../fd_acc_mgr.h" -#include "../fd_system_ids.h" -#include "../../fd_flamenco_base.h" /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/stake_weighted_timestamp.rs#L14 */ #define MAX_ALLOWABLE_DRIFT_FAST ( 25 ) @@ -13,7 +9,7 @@ #define MAX_ALLOWABLE_DRIFT_SLOW ( 150 ) /* Do all intermediate calculations at nanosecond precision, to mirror Solana's behaviour. */ -#define NS_IN_S ( 1000000000 ) +#define NS_IN_S ((long)1e9) /* The target tick duration, derived from the target tick rate. https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/src/poh_config.rs#L32 @@ -29,63 +25,17 @@ timestamp_from_genesis( fd_bank_t * bank ) { } void -fd_sysvar_clock_write( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_sol_sysvar_clock_t * clock ) { - ulong sz = fd_sol_sysvar_clock_size( clock ); - uchar enc[sz]; - memset( enc, 0, sz ); - fd_bincode_encode_ctx_t ctx; - ctx.data = enc; - ctx.dataend = enc + sz; - if( fd_sol_sysvar_clock_encode( clock, &ctx ) ) - FD_LOG_ERR(("fd_sol_sysvar_clock_encode failed")); - - fd_sysvar_set( bank, funk, funk_txn, &fd_sysvar_owner_id, (fd_pubkey_t *) &fd_sysvar_clock_id, enc, sz, fd_bank_slot_get( bank ) ); -} - - -fd_sol_sysvar_clock_t const * -fd_sysvar_clock_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( acc ); - int rc = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_clock_id, funk, funk_txn ); - if( FD_UNLIKELY( rc!=FD_ACC_MGR_SUCCESS ) ) { - return NULL; - } - - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc )==0 ) ) { - return NULL; - } - - int err; - return fd_bincode_decode_spad( - sol_sysvar_clock, spad, - acc->vt->get_data( acc ), - acc->vt->get_data_len( acc ), - &err ); -} - -void -fd_sysvar_clock_init( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn ) { - long timestamp = timestamp_from_genesis( bank ); +fd_sysvar_clock_init( fd_exec_slot_ctx_t * slot_ctx ) { + long timestamp = timestamp_from_genesis( slot_ctx->bank ); fd_sol_sysvar_clock_t clock = { - .slot = fd_bank_slot_get( bank ), + .slot = fd_bank_slot_get( slot_ctx->bank ), .epoch = 0, .epoch_start_timestamp = timestamp, .leader_schedule_epoch = 1, .unix_timestamp = timestamp, }; - fd_sysvar_clock_write( bank, funk, funk_txn, &clock ); + fd_sysvar_clock_write( slot_ctx, &clock ); } /* Bounds the timestamp estimate by the max allowable drift from the expected PoH slot duration. @@ -179,19 +129,20 @@ FD_FN_CONST static inline int valcmp (VAL_T a, VAL_T b) { #include "../../../util/tmpl/fd_treap.c" /* https://github.com/solana-labs/solana/blob/c091fd3da8014c0ef83b626318018f238f506435/runtime/src/bank.rs#L3600 */ -static void -fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - long * result_timestamp, - uint fix_estimate_into_u64, - fd_spad_t * runtime_spad ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { +void +fd_calculate_stake_weighted_timestamp( fd_exec_slot_ctx_t * slot_ctx, + long * result_timestamp, + fd_spad_t * spad ) { + fd_sysvar_cache_t const * sysvar_cache = NULL; + + fd_bank_t * bank = slot_ctx->bank; + + fd_sol_sysvar_clock_t const clock = fd_sysvar_clock_read_nofail( sysvar_cache ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( sysvar_cache ); + + FD_SPAD_FRAME_BEGIN( spad ) { ulong slot_duration = (ulong)fd_bank_ns_per_slot_get( bank ); - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( funk, - funk_txn, - runtime_spad ); // get the unique timestamps /* stake per timestamp */ @@ -199,7 +150,7 @@ fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, /* FIXME: Hardcoded constant */ stake_ts_treap_t _treap[1]; stake_ts_treap_t * treap = stake_ts_treap_join( stake_ts_treap_new( _treap, 10240UL ) ); - uchar * pool_mem = fd_spad_alloc( runtime_spad, stake_ts_pool_align(), stake_ts_pool_footprint( 10240UL ) ); + uchar * pool_mem = fd_spad_alloc( spad, stake_ts_pool_align(), stake_ts_pool_footprint( 10240UL ) ); stake_ts_ele_t * pool = stake_ts_pool_join( stake_ts_pool_new( pool_mem, 10240UL ) ); uint txn_cnt = (uint)fd_bank_transaction_count_get( bank ); @@ -246,7 +197,7 @@ fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, ulong data_len = n->elem.value.data_len; fd_vote_state_versioned_t * vsv = fd_bincode_decode_spad( - vote_state_versioned, runtime_spad, + vote_state_versioned, spad, data, data_len, &err ); @@ -277,9 +228,8 @@ fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, vote_slot = vote_acc_node->elem.slot; } - ulong slot_delta = fd_ulong_sat_sub(fd_bank_slot_get( bank ), vote_slot); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( bank ); - if( slot_delta > epoch_schedule->slots_per_epoch ) { + ulong slot_delta = fd_ulong_sat_sub( fd_bank_slot_get( bank ), vote_slot ); + if( slot_delta > epoch_schedule.slots_per_epoch ) { continue; } @@ -325,77 +275,60 @@ fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, FD_LOG_DEBUG(( "stake weighted timestamp: %ld total stake %lu", *result_timestamp, total_stake )); + int const fix_estimate_into_u64 = FD_FEATURE_ACTIVE_BANK( bank, warp_timestamp_again ); + // Bound estimate by `max_allowable_drift` since the start of the epoch - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( bank ); - ulong epoch_start_slot = fd_epoch_slot0( epoch_schedule, clock->epoch ); + ulong epoch_start_slot = fd_epoch_slot0( &epoch_schedule, clock.epoch ); FD_LOG_DEBUG(( "Epoch start slot %lu", epoch_start_slot )); ulong poh_estimate_offset = fd_ulong_sat_mul( slot_duration, fd_ulong_sat_sub( fd_bank_slot_get( bank ), epoch_start_slot ) ); - ulong estimate_offset = fd_ulong_sat_mul( NS_IN_S, (fix_estimate_into_u64) ? fd_ulong_sat_sub( (ulong)*result_timestamp, (ulong)clock->epoch_start_timestamp ) : (ulong)(*result_timestamp - clock->epoch_start_timestamp)); + ulong estimate_offset = fd_ulong_sat_mul( NS_IN_S, (fix_estimate_into_u64) ? fd_ulong_sat_sub( (ulong)*result_timestamp, (ulong)clock.epoch_start_timestamp ) : (ulong)(*result_timestamp - clock.epoch_start_timestamp)); ulong max_delta_fast = fd_ulong_sat_mul( poh_estimate_offset, MAX_ALLOWABLE_DRIFT_FAST ) / 100; ulong max_delta_slow = fd_ulong_sat_mul( poh_estimate_offset, MAX_ALLOWABLE_DRIFT_SLOW ) / 100; FD_LOG_DEBUG(( "poh offset %lu estimate %lu fast %lu slow %lu", poh_estimate_offset, estimate_offset, max_delta_fast, max_delta_slow )); if( estimate_offset > poh_estimate_offset && fd_ulong_sat_sub(estimate_offset, poh_estimate_offset) > max_delta_slow ) { - *result_timestamp = clock->epoch_start_timestamp + (long)poh_estimate_offset / NS_IN_S + (long)max_delta_slow / NS_IN_S; + *result_timestamp = clock.epoch_start_timestamp + (long)poh_estimate_offset / NS_IN_S + (long)max_delta_slow / NS_IN_S; } else if( estimate_offset < poh_estimate_offset && fd_ulong_sat_sub(poh_estimate_offset, estimate_offset) > max_delta_fast ) { - *result_timestamp = clock->epoch_start_timestamp + (long)poh_estimate_offset / NS_IN_S - (long)max_delta_fast / NS_IN_S; + *result_timestamp = clock.epoch_start_timestamp + (long)poh_estimate_offset / NS_IN_S - (long)max_delta_fast / NS_IN_S; } - if (*result_timestamp < clock->unix_timestamp) { + if (*result_timestamp < clock.unix_timestamp) { FD_LOG_DEBUG(( "updated timestamp to ancestor" )); - *result_timestamp = clock->unix_timestamp; + *result_timestamp = clock.unix_timestamp; } return; } FD_SPAD_FRAME_END; } -int -fd_sysvar_clock_update( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * runtime_spad ) { - - fd_pubkey_t const * key = &fd_sysvar_clock_id; +void +fd_sysvar_clock_update( fd_exec_slot_ctx_t * slot_ctx, + fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( rec ); - int err = fd_txn_account_init_from_funk_readonly( rec, key, funk, funk_txn ); - if( FD_UNLIKELY( err ) ) { - FD_LOG_ERR(( "fd_txn_account_init_from_funk_readonly(clock) failed: %d", err )); - } + fd_bank_t * bank = slot_ctx->bank; + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( bank ); - fd_sol_sysvar_clock_t * clock = fd_bincode_decode_spad( - sol_sysvar_clock, runtime_spad, - rec->vt->get_data( rec ), - rec->vt->get_data_len( rec ), - &err ); - if( FD_UNLIKELY( err ) ) { - FD_LOG_ERR(( "fd_sol_sysvar_clock_decode failed" )); - } + fd_sol_sysvar_clock_t clock = fd_sysvar_clock_read_nofail( sysvar_cache ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( sysvar_cache ); - long ancestor_timestamp = clock->unix_timestamp; + long ancestor_timestamp = clock.unix_timestamp; if( fd_bank_slot_get( bank ) != 0 ) { long new_timestamp = 0L; - fd_calculate_stake_weighted_timestamp( bank, - funk, - funk_txn, - &new_timestamp, - FD_FEATURE_ACTIVE_BANK( bank, warp_timestamp_again ), - runtime_spad ); + fd_calculate_stake_weighted_timestamp( slot_ctx, &new_timestamp, spad ); /* If the timestamp was successfully calculated, use it. It not keep the old one. https://github.com/anza-xyz/agave/blob/v2.1.14/runtime/src/bank.rs#L1947-L1954 */ if( FD_LIKELY( new_timestamp ) ) { - clock->unix_timestamp = new_timestamp; + clock.unix_timestamp = new_timestamp; } } - if( FD_UNLIKELY( !clock->unix_timestamp ) ) { + if( FD_UNLIKELY( !clock.unix_timestamp ) ) { /* generate timestamp for genesis */ long timestamp_estimate = estimate_timestamp( bank ); long bounded_timestamp_estimate = bound_timestamp_estimate( bank, timestamp_estimate, - clock->epoch_start_timestamp ); + clock.epoch_start_timestamp ); if( timestamp_estimate != bounded_timestamp_estimate ) { FD_LOG_INFO(( "corrected timestamp_estimate %ld to %ld", timestamp_estimate, bounded_timestamp_estimate )); } @@ -411,61 +344,23 @@ fd_sysvar_clock_update( fd_bank_t * bank, FD_LOG_DEBUG(( "clock rewind detected: %ld -> %ld", ancestor_timestamp, bounded_timestamp_estimate )); bounded_timestamp_estimate = ancestor_timestamp; } - clock->unix_timestamp = bounded_timestamp_estimate; + clock.unix_timestamp = bounded_timestamp_estimate; } - clock->slot = fd_bank_slot_get( bank ); + clock.slot = fd_bank_slot_get( bank ); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( bank ); - - ulong epoch_old = clock->epoch; - ulong epoch_new = fd_slot_to_epoch( epoch_schedule, clock->slot, NULL ); - FD_LOG_DEBUG(("Epoch old %lu new %lu slot %lu", epoch_old, epoch_new, clock->slot)); - clock->epoch = epoch_new; + ulong epoch_old = clock.epoch; + ulong epoch_new = fd_slot_to_epoch( &epoch_schedule, clock.slot, NULL ); + clock.epoch = epoch_new; if( epoch_old != epoch_new ) { long timestamp_estimate = 0L; - fd_calculate_stake_weighted_timestamp( bank, - funk, - funk_txn, + fd_calculate_stake_weighted_timestamp( slot_ctx, ×tamp_estimate, - FD_FEATURE_ACTIVE_BANK( bank, warp_timestamp_again ), - runtime_spad ); - clock->unix_timestamp = fd_long_max( timestamp_estimate, ancestor_timestamp ); - clock->epoch_start_timestamp = clock->unix_timestamp; - clock->leader_schedule_epoch = fd_slot_to_leader_schedule_epoch( epoch_schedule, fd_bank_slot_get( bank ) ); - } - - FD_LOG_DEBUG(( "clock->slot: %lu", clock->slot )); - FD_LOG_DEBUG(( "clock->epoch_start_timestamp: %ld", clock->epoch_start_timestamp )); - FD_LOG_DEBUG(( "clock->epoch: %lu", clock->epoch )); - FD_LOG_DEBUG(( "clock->leader_schedule_epoch: %lu", clock->leader_schedule_epoch )); - FD_LOG_DEBUG(( "clock->unix_timestamp: %ld", clock->unix_timestamp )); - - ulong sz = fd_sol_sysvar_clock_size( clock ); - FD_TXN_ACCOUNT_DECL( acc ); - err = fd_txn_account_init_from_funk_mutable( acc, key, funk, funk_txn, 1, sz ); - if( err ) { - FD_LOG_CRIT(( "fd_txn_account_init_from_funk_mutable(clock) failed: %d", err )); + spad ); + clock.unix_timestamp = fd_long_max( timestamp_estimate, ancestor_timestamp ); + clock.epoch_start_timestamp = clock.unix_timestamp; + clock.leader_schedule_epoch = fd_slot_to_leader_schedule_epoch( &epoch_schedule, clock.slot ); } - fd_bincode_encode_ctx_t e_ctx = { - .data = acc->vt->get_data_mut( acc ), - .dataend = acc->vt->get_data_mut( acc )+sz, - }; - if( fd_sol_sysvar_clock_encode( clock, &e_ctx ) ) { - return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; - } - - fd_rent_t const * rent = fd_bank_rent_query( bank ); - ulong lamps = fd_rent_exempt_minimum_balance( rent, sz ); - if( acc->vt->get_lamports( acc ) < lamps ) { - acc->vt->set_lamports( acc, lamps ); - } - - acc->vt->set_data_len( acc, sz ); - acc->vt->set_owner( acc, &fd_sysvar_owner_id ); - - fd_txn_account_mutable_fini( acc, funk, funk_txn ); - - return 0; + fd_sysvar_clock_write( slot_ctx, &clock ); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_clock.h b/src/flamenco/runtime/sysvar/fd_sysvar_clock.h index 4fe920aae4..5e21479d48 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_clock.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_clock.h @@ -3,53 +3,32 @@ /* The clock sysvar provides an approximate measure of network time. */ -#include "../../fd_flamenco_base.h" -#include "../context/fd_exec_instr_ctx.h" -#include "fd_sysvar.h" +#include "../context/fd_exec_slot_ctx.h" /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/clock.rs#L10 */ #define FD_SYSVAR_CLOCK_DEFAULT_TICKS_PER_SECOND ( 160UL ) #define FD_SYSVAR_CLOCK_DEFAULT_HASHES_PER_TICK (12500UL) -FD_PROTOTYPES_BEGIN +/* FD_SYSVAR_CLOCK_STAKE_WEIGHTS_MAX specifies the max number of stake + weights processed in a clock update. */ -/* The clock sysvar provides an approximate measure of network time. */ +#define FD_SYSVAR_CLOCK_STAKE_WEIGHTS_MAX (10240UL) -/* Initialize the clock sysvar account. */ +#define FD_SYSVAR_CLOCK_BINCODE_SZ (40UL) -void -fd_sysvar_clock_init( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn ); +#define FD_SYSVAR_CLOCK_OBJ_SZ (sizeof(fd_sol_sysvar_clock_t)) -/* Update the clock sysvar account. This should be called at the start - of every slot, before execution commences. */ +FD_PROTOTYPES_BEGIN -int -fd_sysvar_clock_update( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * runtime_spad ); +/* The clock sysvar provides an approximate measure of network time. */ -/* Writes the current value of the clock sysvar to funk. */ +/* fd_sysvar_clock_init initializes the sysvar account to genesis state. */ void -fd_sysvar_clock_write( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_sol_sysvar_clock_t * clock ); - -/* fd_sysvar_clok_read reads the current value of the rent sysvar from - funk. If the account doesn't exist in funk or if the account - has zero lamports, this function returns NULL. */ - -fd_sol_sysvar_clock_t const * -fd_sysvar_clock_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); +fd_sysvar_clock_init( fd_exec_slot_ctx_t * slot_ctx ); -/* fd_slot_cnt_2day returns the number of slots in two days. - Used in rent collection. */ +/* fd_slot_cnt_2day returns the number of slots in two days. Used in + rent collection. */ static inline ulong fd_slot_cnt_2day( ulong ticks_per_slot ) { @@ -58,6 +37,28 @@ fd_slot_cnt_2day( ulong ticks_per_slot ) { return ticks / ticks_per_slot; } +/* fd_calculate_stake_weighted_timestamp calculates a timestamp + estimate. Does not modify the slot context. Walks all cached vote + accounts (from the "bank") and calculates a unix timestamp estimate. + The estimate is stored into *result_timestamp. spad is used for + scratch allocations (allocates a treap of size FD_SYSVAR_CLOCK_STAKE_WEIGHTS_MAX). + Crashes the process with FD_LOG_ERR on failure (e.g. too many vote + accounts). */ + +void +fd_calculate_stake_weighted_timestamp( fd_exec_slot_ctx_t * slot_ctx, + long * result_timestamp, + fd_spad_t * spad ); + +/* fd_sysvar_clock_update updates the clock sysvar account. Runs + fd_calculate_stake_weighted_timestamp under the hood. Should be + called at the start of every slot before execution commences. + Crashes the process with FD_LOG_ERR on failure. */ + +void +fd_sysvar_clock_update( fd_exec_slot_ctx_t * slot_ctx, + fd_spad_t * spad ); + FD_PROTOTYPES_END #endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_clock_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c index 56331c8aea..3dba9c2ee0 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c @@ -1,61 +1,16 @@ #include "fd_sysvar_epoch_rewards.h" -#include "fd_sysvar.h" -#include "../fd_acc_mgr.h" -#include "../fd_runtime.h" -#include "../fd_borrowed_account.h" -#include "../fd_system_ids.h" - -static void -write_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_sysvar_epoch_rewards_t * epoch_rewards ) { - ulong sz = fd_sysvar_epoch_rewards_size( epoch_rewards ); - uchar enc[sz]; - fd_memset( enc, 0, sz ); - fd_bincode_encode_ctx_t ctx = { - .data = enc, - .dataend = enc + sz - }; - if( FD_UNLIKELY( fd_sysvar_epoch_rewards_encode( epoch_rewards, &ctx ) ) ) { - FD_LOG_ERR(( "fd_sysvar_epoch_rewards_encode failed" )); - } - - fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_epoch_rewards_id, enc, sz, fd_bank_slot_get( slot_ctx->bank ) ); -} - -fd_sysvar_epoch_rewards_t * -fd_sysvar_epoch_rewards_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( acc ); - int err = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_epoch_rewards_id, funk, funk_txn ); - if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) { - return NULL; - } - - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc ) == 0UL ) ) { - return NULL; - } - - return fd_bincode_decode_spad( - sysvar_epoch_rewards, spad, - acc->vt->get_data( acc ), - acc->vt->get_data_len( acc ), - &err ); -} +#include "fd_sysvar_cache.h" +#include "../context/fd_exec_slot_ctx.h" /* Since there are multiple sysvar epoch rewards updates within a single slot, we need to ensure that the cache stays updated after each change (versus with other sysvars which only get updated once per slot and then synced up after) */ void fd_sysvar_epoch_rewards_distribute( fd_exec_slot_ctx_t * slot_ctx, - ulong distributed, - fd_spad_t * runtime_spad ) { - fd_sysvar_epoch_rewards_t * epoch_rewards = fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); - if( FD_UNLIKELY( epoch_rewards == NULL ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); + ulong distributed ) { + fd_sysvar_epoch_rewards_t epoch_rewards[1]; + if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( fd_bank_sysvar_cache_query( slot_ctx->bank ), epoch_rewards ) ) ) { + FD_LOG_ERR(( "fd_sysvar_epoch_rewards_read failed" )); } if( FD_UNLIKELY( !epoch_rewards->active ) ) { @@ -68,15 +23,14 @@ fd_sysvar_epoch_rewards_distribute( fd_exec_slot_ctx_t * slot_ctx, epoch_rewards->distributed_rewards += distributed; - write_epoch_rewards( slot_ctx, epoch_rewards ); + fd_sysvar_epoch_rewards_write( slot_ctx, epoch_rewards ); } void -fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ) { - fd_sysvar_epoch_rewards_t * epoch_rewards = fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); - if( FD_UNLIKELY( epoch_rewards == NULL ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); +fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx ) { + fd_sysvar_epoch_rewards_t epoch_rewards[1]; + if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( fd_bank_sysvar_cache_query( slot_ctx->bank ), epoch_rewards ) ) ) { + FD_LOG_ERR(( "fd_sysvar_epoch_rewards_read failed" )); } if( FD_UNLIKELY( epoch_rewards->total_rewards < epoch_rewards->distributed_rewards ) ) { @@ -85,7 +39,7 @@ fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx, epoch_rewards->active = 0; - write_epoch_rewards( slot_ctx, epoch_rewards ); + fd_sysvar_epoch_rewards_write( slot_ctx, epoch_rewards ); } /* Create EpochRewards sysvar with calculated rewards @@ -113,5 +67,5 @@ fd_sysvar_epoch_rewards_init( fd_exec_slot_ctx_t * slot_ctx, fd_memcpy( &epoch_rewards.parent_blockhash, last_blockhash, FD_HASH_FOOTPRINT ); - write_epoch_rewards( slot_ctx, &epoch_rewards ); + fd_sysvar_epoch_rewards_write( slot_ctx, &epoch_rewards ); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.h b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.h index 1ba356f63e..f9a1138adf 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.h @@ -3,33 +3,25 @@ #include "../../fd_flamenco_base.h" #include "../../types/fd_types.h" -#include "../context/fd_exec_slot_ctx.h" -FD_PROTOTYPES_BEGIN +#define FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ (81UL) -/* fd_sysvar_epoch_rewards_read reads the current value of the rent - sysvar from funk. If the account doesn't exist in funk or if the account - has zero lamports, this function returns NULL. */ +#define FD_SYSVAR_EPOCH_REWARDS_OBJ_SZ (sizeof(fd_sysvar_epoch_rewards_t)) -fd_sysvar_epoch_rewards_t * -fd_sysvar_epoch_rewards_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); +FD_PROTOTYPES_BEGIN /* Update EpochRewards sysvar with distributed rewards https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/sdk/program/src/epoch_rewards.rs#L44 */ void fd_sysvar_epoch_rewards_distribute( fd_exec_slot_ctx_t * slot_ctx, - ulong distributed, - fd_spad_t * runtime_spad ); + ulong distributed ); /* Set the EpochRewards sysvar to inactive https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/runtime/src/bank/partitioned_epoch_rewards/sysvar.rs#L82 */ void -fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ); +fd_sysvar_epoch_rewards_set_inactive( fd_exec_slot_ctx_t * slot_ctx ); /* Initialize the EpochRewards sysvar account diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c index 1f7aae0b4f..4fbc78c200 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c @@ -1,7 +1,5 @@ #include "fd_sysvar_epoch_schedule.h" -#include "fd_sysvar.h" -#include "../fd_system_ids.h" -#include "../context/fd_exec_slot_ctx.h" + fd_epoch_schedule_t * fd_epoch_schedule_derive( fd_epoch_schedule_t * schedule, ulong epoch_len, @@ -30,57 +28,6 @@ fd_epoch_schedule_derive( fd_epoch_schedule_t * schedule, return schedule; } -void -fd_sysvar_epoch_schedule_write( fd_exec_slot_ctx_t * slot_ctx, - fd_epoch_schedule_t const * epoch_schedule ) { - ulong sz = fd_epoch_schedule_size( epoch_schedule ); - FD_LOG_INFO(("Writing epoch schedule size %lu", sz)); - /* TODO remove alloca */ - uchar enc[ sz ]; - memset( enc, 0, sz ); - fd_bincode_encode_ctx_t ctx = { - .data = enc, - .dataend = enc + sz - }; - if( fd_epoch_schedule_encode( epoch_schedule, &ctx ) ) { - FD_LOG_ERR(("fd_epoch_schedule_encode failed")); - } - - fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_epoch_schedule_id, enc, sz, fd_bank_slot_get( slot_ctx->bank ) ); -} - -fd_epoch_schedule_t * -fd_sysvar_epoch_schedule_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - - FD_TXN_ACCOUNT_DECL( acc ); - int err = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_epoch_schedule_id, funk, funk_txn ); - if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) { - return NULL; - } - - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc ) == 0UL ) ) { - return NULL; - } - - return fd_bincode_decode_spad( - epoch_schedule, spad, - acc->vt->get_data( acc ), - acc->vt->get_data_len( acc ), - &err ); -} - -void -fd_sysvar_epoch_schedule_init( fd_exec_slot_ctx_t * slot_ctx ) { - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - fd_sysvar_epoch_schedule_write( slot_ctx, epoch_schedule ); -} - /* https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/sdk/program/src/epoch_schedule.rs#L105 */ ulong diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h index 7c47c4de10..e2d418daac 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h @@ -52,29 +52,11 @@ #define FD_EPOCH_LEN_MAX (0xFFFFFFFFUL) -FD_PROTOTYPES_BEGIN - -/* fd_sysvar_epoch_schedule_init initializes the epoch schedule sysvar - account. FIXME document what this actually does. */ +#define FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ (33UL) -void -fd_sysvar_epoch_schedule_init( fd_exec_slot_ctx_t * slot_ctx ); +#define FD_SYSVAR_EPOCH_SCHEDULE_OBJ_SZ (sizeof(fd_epoch_schedule_t)) -/* fd_sysvar_epoch_schedule_read reads the current value of the rent - sysvar from funk. If the account doesn't exist in funk or if the account - has zero lamports, this function returns NULL. */ - -fd_epoch_schedule_t * -fd_sysvar_epoch_schedule_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); - -/* fd_sysvar_epoch_schedule_write writes the current value of the epoch - schedule sysvar to funk. */ - -void -fd_sysvar_epoch_schedule_write( fd_exec_slot_ctx_t * slot_ctx, - fd_epoch_schedule_t const * epoch_schedule ); +FD_PROTOTYPES_BEGIN /* fd_epoch_schedule_derive derives an epoch schedule config from the given parameters. New epoch schedule configurations should only be diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h b/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h index 0cc3da58d6..8fdf2ced90 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_instructions.h @@ -2,7 +2,6 @@ #define HEADER_fd_src_flamenco_runtime_sysvar_instructions_h #include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" #include "../info/fd_instr_info.h" FD_PROTOTYPES_BEGIN diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.c b/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.c index f7767904f9..e0a5abe4da 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.c @@ -1,8 +1,6 @@ #include "fd_sysvar_last_restart_slot.h" #include "../../types/fd_types.h" -#include "fd_sysvar.h" -#include "../fd_system_ids.h" -#include "../fd_runtime.h" +#include "../context/fd_exec_slot_ctx.h" void fd_sysvar_last_restart_slot_init( fd_exec_slot_ctx_t * slot_ctx ) { @@ -12,82 +10,57 @@ fd_sysvar_last_restart_slot_init( fd_exec_slot_ctx_t * slot_ctx ) { return; } + fd_sol_sysvar_last_restart_slot_t sysvar = {0}; + fd_sysvar_last_restart_slot_write( slot_ctx, &sysvar ); +} - ulong sz = fd_sol_sysvar_last_restart_slot_size( fd_bank_last_restart_slot_query( slot_ctx->bank ) ); - uchar enc[ sz ]; - fd_memset( enc, 0, sz ); - - fd_bincode_encode_ctx_t encode = { - .data = enc, - .dataend = enc + sz, - }; - int err = fd_sol_sysvar_last_restart_slot_encode( fd_bank_last_restart_slot_query( slot_ctx->bank ), &encode ); - FD_TEST( err==FD_BINCODE_SUCCESS ); +/* https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2217 */ - fd_sysvar_set( slot_ctx->bank, - slot_ctx->funk, - slot_ctx->funk_txn, - &fd_sysvar_owner_id, - &fd_sysvar_last_restart_slot_id, - enc, sz, - fd_bank_slot_get( slot_ctx->bank ) ); -} +ulong +fd_sysvar_last_restart_slot_derive( + fd_hard_forks_global_t const * hard_forks, + ulong current_slot +) { -fd_sol_sysvar_last_restart_slot_t * -fd_sysvar_last_restart_slot_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { + if( FD_UNLIKELY( hard_forks->hard_forks_len == 0 ) ) { + /* SIMD-0047: The first restart slot should be `0` */ + return 0UL; + } - FD_TXN_ACCOUNT_DECL( acc ); - int err = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_last_restart_slot_id, funk, funk_txn ); - if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) return NULL; + fd_slot_pair_t const * head = fd_hard_forks_hard_forks_join( (fd_hard_forks_global_t *)hard_forks ); + fd_slot_pair_t const * tail = head + hard_forks->hard_forks_len - 1UL; - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc )==0 ) ) return NULL; + for( fd_slot_pair_t const *pair = tail; pair >= head; pair-- ) { + if( pair->slot <= current_slot ) { + return pair->slot; + } + } - return fd_bincode_decode_spad( - sol_sysvar_last_restart_slot, spad, - acc->vt->get_data( acc ), - acc->vt->get_data_len( acc ), - &err ); + return 0UL; } /* fd_sysvar_last_restart_slot_update is equivalent to Agave's solana_runtime::bank::Bank::update_last_restart_slot */ void -fd_sysvar_last_restart_slot_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { +fd_sysvar_last_restart_slot_update( + fd_exec_slot_ctx_t * slot_ctx, + ulong last_restart_slot_want +) { /* https://github.com/solana-labs/solana/blob/v1.18.18/runtime/src/bank.rs#L2093-L2095 */ if( !FD_FEATURE_ACTIVE_BANK( slot_ctx->bank, last_restart_slot_sysvar ) ) return; - int has_current_last_restart_slot = 0; - ulong current_last_restart_slot = 0UL; - /* https://github.com/solana-labs/solana/blob/v1.18.18/runtime/src/bank.rs#L2098-L2106 */ - fd_sol_sysvar_last_restart_slot_t * old_account = fd_sysvar_last_restart_slot_read( slot_ctx->funk, - slot_ctx->funk_txn, - runtime_spad ); - ulong old_account_slot = old_account ? old_account->slot : 0UL; - has_current_last_restart_slot = 1; - current_last_restart_slot = old_account_slot; - - /* https://github.com/solana-labs/solana/blob/v1.18.18/runtime/src/bank.rs#L2108-L2120 */ - /* FIXME: Query hard forks list */ - ulong last_restart_slot = fd_bank_last_restart_slot_get( slot_ctx->bank ).slot; + ulong last_restart_slot_have = ULONG_MAX; + fd_sol_sysvar_last_restart_slot_t sysvar; + if( FD_LIKELY( fd_sysvar_last_restart_slot_read( fd_bank_sysvar_cache_query( slot_ctx->bank ), &sysvar ) ) ) { + last_restart_slot_have = sysvar.slot; + } /* https://github.com/solana-labs/solana/blob/v1.18.18/runtime/src/bank.rs#L2122-L2130 */ - if( !has_current_last_restart_slot || current_last_restart_slot != last_restart_slot ) { - fd_sysvar_set( slot_ctx->bank, - slot_ctx->funk, - slot_ctx->funk_txn, - &fd_sysvar_owner_id, - &fd_sysvar_last_restart_slot_id, - &last_restart_slot, - sizeof(ulong), - fd_bank_slot_get( slot_ctx->bank ) ); + if( last_restart_slot_have != last_restart_slot_want ) { + sysvar.slot = last_restart_slot_want; + fd_sysvar_last_restart_slot_write( slot_ctx, &sysvar ); } } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.h b/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.h index 3c9ede4f6a..4af326c290 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.h @@ -2,8 +2,12 @@ #define HEADER_fd_src_flamenco_runtime_fd_sysvar_last_restart_slot_h #include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" -#include "../context/fd_exec_slot_ctx.h" + +typedef struct fd_hard_forks_global fd_hard_forks_global_t; + +#define FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ (8UL) + +#define FD_SYSVAR_LAST_RESTART_SLOT_OBJ_SZ (sizeof(fd_sol_sysvar_last_restart_slot_t)) FD_PROTOTYPES_BEGIN @@ -14,20 +18,25 @@ FD_PROTOTYPES_BEGIN void fd_sysvar_last_restart_slot_init( fd_exec_slot_ctx_t * slot_ctx ); -/* fd_sysvar_last_restart_slot_update performs a sysvar update before - transaction processing. TODO not completely implemented. */ +/* fd_sysvar_last_restart_slot_update ensures the "last restart slot" + sysvar contains the given slot number, writing to the sysvar account + if necessary. + See Agave's solana_runtime::bank::Bank::update_last_restart_slot */ void -fd_sysvar_last_restart_slot_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ); - -/* fd_sysvar_last_restart_slot_read queries the last restart slot sysvar - from the given funk. If the account doesn't exist in funk or if the - account has zero lamports, this function returns NULL. */ - -fd_sol_sysvar_last_restart_slot_t * -fd_sysvar_last_restart_slot_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); +fd_sysvar_last_restart_slot_update( + fd_exec_slot_ctx_t * slot_ctx, + ulong last_restart_slot +); + +/* fd_sysvar_last_restart_slot_derive derives the "last restart slot" + value (return value) from a bank's "hard forks" list. */ + +ulong +fd_sysvar_last_restart_slot_derive( + fd_hard_forks_global_t const * hard_forks, + ulong current_slot +); FD_PROTOTYPES_END diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c index 1f0fc563a3..b9cdcef668 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c @@ -1,185 +1,80 @@ -#include -#include "../fd_acc_mgr.h" -#include "../fd_hashes.h" -#include "fd_sysvar.h" -#include "../fd_runtime.h" -#include "../fd_system_ids.h" +#include "fd_sysvar_recent_hashes.h" #include "../context/fd_exec_slot_ctx.h" +#include "../fd_system_ids.h" +#include "fd_sysvar_cache.h" -#define FD_RECENT_BLOCKHASHES_ACCOUNT_MAX_SIZE sizeof(ulong) + FD_RECENT_BLOCKHASHES_MAX_ENTRIES * (sizeof(fd_hash_t) + sizeof(ulong)) - -// run --ledger /home/jsiegel/test-ledger --db /home/jsiegel/funk --cmd accounts --accounts /home/jsiegel/test-ledger/accounts/ --pages 15 --index-max 120000000 --start-slot 2 --end-slot 2 --start-id 35 --end-id 37 -// run --ledger /home/jsiegel/test-ledger --db /home/jsiegel/funk --cmd replay --pages 15 --index-max 120000000 --start-slot 0 --end-slot 3 - -// {meta = {write_version_obsolete = 137, -// data_len = 6008, pubkey = "\006\247\325\027\031,V\216\340\212\204_sÒ—\210\317\003\\1E\262\032\263D\330\006.\251@\000"}, info = {lamports = 42706560, rent_epoch = 0, owner = "\006\247\325\027\030u\367)\307=\223@\217!a \006~ØŒv\340\214(\177\301\224`\000\000\000", executable = 0 '\000', padding = "K\000\f\376\177\000"}, hash = {value = "\302Q\316\035qTY\347\352]\260\335\213\224R\227Ô¯\366R\273\063H\345Ö‘c\377\207/k\275"}} - -// owner: Sysvar1111111111111111111111111111111111111 pubkey: SysvarRecentB1ockHashes11111111111111111111 hash: E5YSehyvJ7xXcNnQjWCH9UhMJ1dxDBJ1RuuPh1Y3RZgg file: /home/jsiegel/test-ledger/accounts//2.37 -// {blockhash = JCidNXtcMXMWQwMDM3ZQq5pxaw3hQpNbeHg1KcstjuF4, fee_calculator={lamports_per_signature = 5000}} -// {blockhash = GQN3oV8G1Ra3GCX76dE1YYJ6UjMyDreNCEWM4tZ39zj1, fee_calculator={lamports_per_signature = 5000}} -// {blockhash = Ha5DVgnD1xSA8oQc337jtA3atEfQ4TFX1ajeZG1Y2tUx, fee_calculator={lamports_per_signature = 0}} - -/* Skips fd_types encoding preflight checks and directly serializes the blockhash queue into a buffer representing - account data for the recent blockhashes sysvar. */ +/* Skips fd_types encoding preflight checks and directly serializes the + blockhash queue into a buffer representing account data for the + recent blockhashes sysvar. */ static void -encode_rbh_from_blockhash_queue( fd_exec_slot_ctx_t * slot_ctx, uchar * enc ) { - fd_block_hash_queue_global_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank ); +encode_rbh_from_blockhash_queue( fd_exec_slot_ctx_t * slot_ctx, + uchar out_mem[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] ) { + fd_blockhashes_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_block_hash_queue_ages_pool_join( bhq ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = fd_block_hash_queue_ages_root_join( bhq ); + ulong queue_sz = fd_blockhash_deq_cnt( bhq->d.deque ); + ulong out_max = fd_ulong_min( queue_sz, FD_SYSVAR_RECENT_HASHES_CAP ); - ulong queue_sz = fd_hash_hash_age_pair_t_map_size( ages_pool, ages_root ); - ulong hashes_len = fd_ulong_min( queue_sz, FD_RECENT_BLOCKHASHES_MAX_ENTRIES ); - fd_memcpy( enc, &hashes_len, sizeof(ulong) ); + uchar * enc = out_mem; + fd_memcpy( enc, &out_max, sizeof(ulong) ); enc += sizeof(ulong); /* Iterate over blockhash queue and encode the recent blockhashes. We can do direct memcpying and avoid redundant checks from fd_types encoders since the enc buffer is already sized out to the worst-case bound. */ - fd_hash_hash_age_pair_t_mapnode_t const * nn; - for( fd_hash_hash_age_pair_t_mapnode_t const * n = fd_hash_hash_age_pair_t_map_minimum_const( ages_pool, ages_root ); n; n = nn ) { - nn = fd_hash_hash_age_pair_t_map_successor_const( ages_pool, n ); - ulong enc_idx = bhq->last_hash_index - n->elem.val.hash_index; - if( enc_idx>=hashes_len ) { - continue; - } - fd_hash_t hash = n->elem.key; - ulong lps = n->elem.val.fee_calculator.lamports_per_signature; - - fd_memcpy( enc + enc_idx * (FD_HASH_FOOTPRINT + sizeof(ulong)), &hash, FD_HASH_FOOTPRINT ); - fd_memcpy( enc + enc_idx * (FD_HASH_FOOTPRINT + sizeof(ulong)) + sizeof(fd_hash_t), &lps, sizeof(ulong) ); + ulong out_idx = 0UL; + for( fd_blockhash_deq_iter_t iter = fd_blockhash_deq_iter_init_rev( bhq->d.deque ); + out_idxd.deque, iter ); + out_idx++, iter = fd_blockhash_deq_iter_prev( bhq->d.deque, iter ) ) { + fd_blockhash_info_t const * n = fd_blockhash_deq_iter_ele_const( bhq->d.deque, iter ); + fd_memcpy( enc, n->hash.uc, 32 ); + FD_STORE( ulong, enc+32, n->fee_calculator.lamports_per_signature ); + out_idx++; + enc += 40; } } -// https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/fee_calculator.rs#L110 void -fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ) { +fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { + ulong sz_max = 0UL; + uchar * data = fd_sysvar_cache_data_modify_prepare( slot_ctx, &fd_sysvar_recent_block_hashes_id, NULL, &sz_max ); + if( FD_UNLIKELY( !data ) ) FD_LOG_ERR(( "fd_sysvar_cache_data_modify_prepare(recent_block_hashes) failed" )); + FD_TEST( sz_max>=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + fd_memset( data, 0, FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + fd_sysvar_cache_data_modify_commit( slot_ctx, &fd_sysvar_recent_block_hashes_id, FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); - if( fd_bank_slot_get( slot_ctx->bank ) != 0 ) { - return; - } - - ulong sz = FD_RECENT_BLOCKHASHES_ACCOUNT_MAX_SIZE; - uchar * enc = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, sz ); - fd_memset( enc, 0, sz ); - encode_rbh_from_blockhash_queue( slot_ctx, enc ); - fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_recent_block_hashes_id, enc, sz, fd_bank_slot_get( slot_ctx->bank ) ); - - } FD_SPAD_FRAME_END; } // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L113 static void -register_blockhash( fd_exec_slot_ctx_t * slot_ctx, fd_hash_t const * hash ) { - - fd_block_hash_queue_global_t * bhq = fd_bank_block_hash_queue_modify( slot_ctx->bank ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_block_hash_queue_ages_pool_join( bhq ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = fd_block_hash_queue_ages_root_join( bhq ); - bhq->last_hash_index++; - if( fd_hash_hash_age_pair_t_map_size( ages_pool, ages_root ) >= bhq->max_age ) { - fd_hash_hash_age_pair_t_mapnode_t * nn; - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( ages_pool, ages_root ); n; n = nn ) { - nn = fd_hash_hash_age_pair_t_map_successor( ages_pool, n ); - /* NOTE: Yes, this check is incorrect. It should be >= which caps the blockhash queue at max_age - entries, but instead max_age + 1 entries are allowed to exist in the queue at once. This mimics - Agave to stay conformant with their implementation. - https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L109 */ - if( bhq->last_hash_index - n->elem.val.hash_index > bhq->max_age ) { - fd_hash_hash_age_pair_t_map_remove( ages_pool, &ages_root, n ); - fd_hash_hash_age_pair_t_map_release( ages_pool, n ); - } - } - } - - fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( ages_pool ); - node->elem = (fd_hash_hash_age_pair_t){ - .key = *hash, - .val = (fd_hash_age_t){ .hash_index = bhq->last_hash_index, .fee_calculator = (fd_fee_calculator_t){ .lamports_per_signature = fd_bank_lamports_per_signature_get( slot_ctx->bank ) }, .timestamp = (ulong)fd_log_wallclock() } +register_blockhash( fd_exec_slot_ctx_t * slot_ctx, + fd_hash_t const * hash ) { + fd_blockhashes_t * bhq = fd_bank_block_hash_queue_modify( slot_ctx->bank ); + fd_blockhash_info_t * bh = fd_blockhashes_push( bhq, hash ); + bh->fee_calculator = (fd_fee_calculator_t){ + .lamports_per_signature = fd_bank_lamports_per_signature_get( slot_ctx->bank ) }; - // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L121-L128 - fd_hash_hash_age_pair_t_map_insert( ages_pool, &ages_root, node ); - // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L130 - fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( bhq ); - fd_memcpy( last_hash, hash, sizeof(fd_hash_t) ); - - fd_block_hash_queue_ages_pool_update( bhq, ages_pool ); - fd_block_hash_queue_ages_root_update( bhq, ages_root ); } -/* This implementation is more consistent with Agave's bank implementation for updating the block hashes sysvar: - 1. Update the block hash queue with the latest poh - 2. Take the first 150 blockhashes from the queue (or fewer if there are) - 3. Manually serialize the recent blockhashes - 4. Set the sysvar account with the new data */ void -fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { - /* Update the blockhash queue */ +fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx ) { + /* Add PoH hash to bank blockhash queue */ register_blockhash( slot_ctx, fd_bank_poh_query( slot_ctx->bank ) ); - /* Derive the new sysvar recent blockhashes from the blockhash queue */ - ulong sz = FD_RECENT_BLOCKHASHES_ACCOUNT_MAX_SIZE; - uchar * enc = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, sz ); - uchar * enc_start = enc; - fd_memset( enc, 0, sz ); - - /* Encode the recent blockhashes */ - encode_rbh_from_blockhash_queue( slot_ctx, enc ); - - /* Set the sysvar from the encoded data */ - fd_sysvar_set( slot_ctx->bank, - slot_ctx->funk, - slot_ctx->funk_txn, - &fd_sysvar_owner_id, - &fd_sysvar_recent_block_hashes_id, - enc_start, - sz, - fd_bank_slot_get( slot_ctx->bank ) ); - } FD_SPAD_FRAME_END; -} - -fd_recent_block_hashes_global_t * -fd_sysvar_recent_hashes_read( fd_funk_t * funk, fd_funk_txn_t * funk_txn, fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( acc ); - int err = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_recent_block_hashes_id, funk, funk_txn ); - if( FD_UNLIKELY( err != FD_ACC_MGR_SUCCESS ) ) - return NULL; - - fd_bincode_decode_ctx_t ctx = { - .data = acc->vt->get_data( acc ), - .dataend = acc->vt->get_data( acc ) + acc->vt->get_data_len( acc ), - }; - - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc ) == 0UL ) ) { - return NULL; - } - - ulong total_sz = 0; - err = fd_recent_block_hashes_decode_footprint( &ctx, &total_sz ); - if( FD_UNLIKELY( err ) ) { - return NULL; - } - - uchar * mem = fd_spad_alloc( spad, fd_recent_block_hashes_align(), total_sz ); - if( FD_UNLIKELY( !mem ) ) { - FD_LOG_CRIT(( "fd_spad_alloc failed" )); - } + /* Update sysvar account with latest 150 hashes */ - /* This would never happen in a real cluster, this is a workaround - for fuzz-generated cases where sysvar accounts are not funded. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc ) == 0 ) ) { - return NULL; + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_cache_flags_exists( sysvar_cache->desc.slot_hashes.flags ) ) ) { + fd_sysvar_recent_hashes_init( slot_ctx ); } - return fd_recent_block_hashes_decode_global( mem, &ctx ); + ulong sz_max = 0UL; + uchar * data = fd_sysvar_cache_data_modify_prepare( slot_ctx, &fd_sysvar_recent_block_hashes_id, NULL, &sz_max ); + if( FD_UNLIKELY( !data ) ) FD_LOG_ERR(( "fd_sysvar_cache_data_modify_prepare(recent_block_hashes) failed" )); + FD_TEST( sz_max>=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + encode_rbh_from_blockhash_queue( slot_ctx, data ); + fd_sysvar_cache_data_modify_commit( slot_ctx, &fd_sysvar_recent_block_hashes_id, FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h index b951e14eb8..95842c7843 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h @@ -1,40 +1,51 @@ -#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_recent_hashes_h -#define HEADER_fd_src_flamenco_runtime_sysvar_fd_recent_hashes_h +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_recent_hashes_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_recent_hashes_h + +/* fd_sysvar_recent_hashes.h manages the "recent block hashes" sysvar + account (address SysvarRecentB1ockHashes11111111111111111111). */ -#include "../../types/fd_types.h" #include "../../fd_flamenco_base.h" -#include "../../../funk/fd_funk.h" /* FD_SYSVAR_RECENT_HASHES_CAP is the max number of block hash entries the recent blockhashes sysvar will include. - https://github.com/anza-xyz/agave/blob/6398ddf6ab8a8f81017bf675ab315a70067f0bf0/sdk/program/src/sysvar/recent_blockhashes.rs#L32 -*/ + https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/recent_blockhashes.rs#L37 */ #define FD_SYSVAR_RECENT_HASHES_CAP (150UL) -FD_PROTOTYPES_BEGIN +/* FD_SYSVAR_RECENT_HASHES_BINCODE_SZ is the serialized size of the + recent block hashes sysvar account. (static/hardcoded) -/* The recent hashes sysvar */ + Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/recent_blockhashes.rs#L157 */ -/* Initialize the recent hashes sysvar account. */ -void -fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ); +#define FD_SYSVAR_RECENT_HASHES_BINCODE_SZ (6008UL) -/* Update the recent hashes sysvar account. This should be called at the start of every slot, before execution commences. */ -void -fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ); +#define FD_SYSVAR_RECENT_HASHES_OBJ_SZ \ + FD_LAYOUT_FINI( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( FD_LAYOUT_APPEND( \ + FD_LAYOUT_APPEND( FD_LAYOUT_INIT, \ + alignof(fd_block_hash_queue_global_t), sizeof(fd_block_hash_queue_global_t) ) \ + alignof(ulong), sizeof(ulong) ) \ + FD_HASH_ALIGN, sizeof(fd_hash_t) ) \ + fd_hash_hash_age_pair_t_map_align(), fd_hash_hash_age_pair_t_map_footprint( 400 ) ) \ + alignof(ulong), sizeof(ulong) ), \ + 128UL ) +FD_PROTOTYPES_BEGIN -/* fd_sysvar_recent_hashes_read reads the recent hashes sysvar from funk. - If the account doesn't exist in funk or if the account has zero - lamports, this function returns NULL. */ +/* fd_sysvar_recent_hashes_init sets the "recent block hashes" sysvar + account to an empty vector. This is used to initialize the runtime + from genesis (FIXME Agave reference). */ -fd_recent_block_hashes_global_t * -fd_sysvar_recent_hashes_read( fd_funk_t * funk, fd_funk_txn_t * funk_txn, fd_spad_t * spad ); +void +fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx ); + +/* fd_sysvar_recent_hashes_update appends an entry to the bank's block + hash queue, and the "recent block hashes" sysvar account. Called + during the slot boundary (at the start of a slot). */ + +void +fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx ); FD_PROTOTYPES_END -#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_recent_hashes_h */ +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_recent_hashes_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_rent.c b/src/flamenco/runtime/sysvar/fd_sysvar_rent.c index 069cfee4a2..5de41a8572 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_rent.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_rent.c @@ -1,56 +1,11 @@ #include "fd_sysvar_rent.h" -#include "fd_sysvar.h" -#include "../fd_system_ids.h" -#include "../context/fd_exec_slot_ctx.h" -#include -void -fd_sysvar_rent_write( fd_exec_slot_ctx_t * slot_ctx, - fd_rent_t const * rent ) { +/* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/rent.rs#L36 */ +#define ACCOUNT_STORAGE_OVERHEAD (128) - uchar enc[ 32 ]; - - ulong sz = fd_rent_size( rent ); - FD_TEST( sz<=sizeof(enc) ); - memset( enc, 0, sz ); - - fd_bincode_encode_ctx_t ctx; - ctx.data = enc; - ctx.dataend = enc + sz; - if( fd_rent_encode( rent, &ctx ) ) - FD_LOG_ERR(("fd_rent_encode failed")); - - fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_rent_id, enc, sz, fd_bank_slot_get( slot_ctx->bank ) ); -} - -void -fd_sysvar_rent_init( fd_exec_slot_ctx_t * slot_ctx ) { - fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank ); - fd_sysvar_rent_write( slot_ctx, rent ); -} - -fd_rent_t const * -fd_sysvar_rent_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( acc ); - int rc = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_rent_id, funk, funk_txn ); - if( FD_UNLIKELY( rc!=FD_ACC_MGR_SUCCESS ) ) { - return NULL; - } - - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( acc->vt->get_lamports( acc )==0 ) ) { - return NULL; - } - - int err; - return fd_bincode_decode_spad( - rent, spad, - acc->vt->get_data( acc ), - acc->vt->get_data_len( acc ), - &err ); +ulong +fd_rent_exempt_minimum_balance( fd_rent_t const * rent, + ulong data_len ) { + /* https://github.com/anza-xyz/agave/blob/d2124a995f89e33c54f41da76bfd5b0bd5820898/sdk/program/src/rent.rs#L74 */ + return fd_rust_cast_double_to_ulong( (double)((data_len + ACCOUNT_STORAGE_OVERHEAD) * rent->lamports_per_uint8_year) * rent->exemption_threshold ); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_rent.h b/src/flamenco/runtime/sysvar/fd_sysvar_rent.h index 726289c70a..9d1b3cdae9 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_rent.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_rent.h @@ -3,7 +3,9 @@ #include "../../fd_flamenco_base.h" #include "../../types/fd_types.h" -#include "../../../funk/fd_funk.h" + +#define FD_SYSVAR_RENT_BINCODE_SZ (17UL) + FD_PROTOTYPES_BEGIN /* fd_sysvar_rent_init copies the cached rent sysvar stored from @@ -13,12 +15,6 @@ FD_PROTOTYPES_BEGIN void fd_sysvar_rent_init( fd_exec_slot_ctx_t * slot_ctx ); -/* fd_sysvar_rent_write writes the current value of the rent sysvar to funk. */ - -void -fd_sysvar_rent_write( fd_exec_slot_ctx_t * slot_ctx, - fd_rent_t const * rent ); - /* fd_rent_exempt_minimum_balance returns the minimum balance needed for an account with the given data_len to be rent exempt. rent points to the current rent parameters. */ @@ -27,15 +23,6 @@ ulong fd_rent_exempt_minimum_balance( fd_rent_t const * rent, ulong data_len ); -/* fd_sysvar_rent_read reads the current value of the rent sysvar from - funk. If the account doesn't exist in funk or if the account - has zero lamports, this function returns NULL. */ - -fd_rent_t const * -fd_sysvar_rent_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); - FD_PROTOTYPES_END #endif /* HEADER_fd_src_flamenco_runtime_fd_sysvar_rent_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_rent1.c b/src/flamenco/runtime/sysvar/fd_sysvar_rent1.c deleted file mode 100644 index e6f3a0f53e..0000000000 --- a/src/flamenco/runtime/sysvar/fd_sysvar_rent1.c +++ /dev/null @@ -1,13 +0,0 @@ -#include "fd_sysvar_rent.h" - -/* Moved into a separate compile unit to minimize dependencies on fd_funk */ - -/* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/rent.rs#L36 */ -#define ACCOUNT_STORAGE_OVERHEAD (128) - -ulong -fd_rent_exempt_minimum_balance( fd_rent_t const * rent, - ulong data_len ) { - /* https://github.com/anza-xyz/agave/blob/d2124a995f89e33c54f41da76bfd5b0bd5820898/sdk/program/src/rent.rs#L74 */ - return fd_rust_cast_double_to_ulong( (double)((data_len + ACCOUNT_STORAGE_OVERHEAD) * rent->lamports_per_uint8_year) * rent->exemption_threshold ); -} diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.c b/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.c index 30f883844e..fd55720c00 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.c @@ -1,107 +1,36 @@ #include "fd_sysvar_slot_hashes.h" -#include "fd_sysvar.h" -#include "../fd_acc_mgr.h" -#include "../fd_borrowed_account.h" +#include "fd_sysvar_cache.h" #include "../fd_system_ids.h" #include "../context/fd_exec_slot_ctx.h" -/* FIXME These constants should be header defines */ - -/* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_hashes.rs#L11 */ -FD_FN_UNUSED static const ulong slot_hashes_max_entries = 512; - -/* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/sysvar/slot_hashes.rs#L12 */ -static const ulong slot_hashes_account_size = 20488; void -fd_sysvar_slot_hashes_write( fd_exec_slot_ctx_t * slot_ctx, - fd_slot_hashes_global_t * slot_hashes_global ) { - uchar enc[slot_hashes_account_size]; - fd_memset( enc, 0, slot_hashes_account_size ); - fd_bincode_encode_ctx_t ctx = { - .data = enc, - .dataend = enc + slot_hashes_account_size, - }; - if( fd_slot_hashes_encode_global( slot_hashes_global, &ctx ) ) { - FD_LOG_ERR(("fd_slot_hashes_encode failed")); - } - fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_slot_hashes_id, enc, slot_hashes_account_size, fd_bank_slot_get( slot_ctx->bank ) ); -} - -ulong -fd_sysvar_slot_hashes_footprint( ulong slot_hashes_cap ) { - return sizeof(fd_slot_hashes_global_t) + - deq_fd_slot_hash_t_footprint( slot_hashes_cap ) + deq_fd_slot_hash_t_align(); +fd_sysvar_slot_hashes_init( fd_exec_slot_ctx_t * slot_ctx ) { + ulong sz_max; + uchar * data = fd_sysvar_cache_data_modify_prepare( slot_ctx, &fd_sysvar_slot_hashes_id, NULL, &sz_max ); + FD_TEST( sz_max>=FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); + fd_memset( data, 0, FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); + fd_sysvar_cache_data_modify_commit( slot_ctx, &fd_sysvar_slot_hashes_id, FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); } -void * -fd_sysvar_slot_hashes_new( void * mem, - ulong slot_hashes_cap ) { - if( FD_UNLIKELY( !mem ) ) { - FD_LOG_ERR(( "Unable to allocate memory for slot hashes" )); - } - if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, FD_SYSVAR_SLOT_HASHES_ALIGN ) ) ) { - FD_LOG_ERR(( "Memory for slot hashes is not aligned" )); - } - - fd_slot_hashes_global_t * slot_hashes_global = (fd_slot_hashes_global_t *)mem; - - uchar * slot_hash_mem = (uchar*)fd_ulong_align_up( (ulong)((uchar *)mem + sizeof(fd_slot_hashes_global_t)), deq_fd_slot_hash_t_align() ); - deq_fd_slot_hash_t_new( (void*)slot_hash_mem, slot_hashes_cap ); - slot_hashes_global->hashes_offset = (ulong)slot_hash_mem - (ulong)slot_hashes_global; - - return slot_hashes_global; -} - -fd_slot_hashes_global_t * -fd_sysvar_slot_hashes_join( void * shmem, - fd_slot_hash_t ** slot_hash ) { - fd_slot_hashes_global_t * slot_hashes_global = (fd_slot_hashes_global_t *)shmem; - *slot_hash = deq_fd_slot_hash_t_join( (uchar*)shmem + slot_hashes_global->hashes_offset ); - - return slot_hashes_global; -} - -void * -fd_sysvar_slot_hashes_leave( fd_slot_hashes_global_t * slot_hashes_global, - fd_slot_hash_t * slot_hash ) { - deq_fd_slot_hash_t_leave( slot_hash ); - - return slot_hashes_global; -} - -void * -fd_sysvar_slot_hashes_delete( void * mem ) { - void * slot_hash_mem = (void *)fd_ulong_align_up( (ulong)((uchar *)mem + sizeof(fd_slot_hashes_global_t)), deq_fd_slot_hash_t_align() ); - deq_fd_slot_hash_t_delete( slot_hash_mem ); - - return mem; -} +/* https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2290 */ void -fd_sysvar_slot_hashes_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { - void * mem = fd_spad_alloc( runtime_spad, FD_SYSVAR_SLOT_HASHES_ALIGN, fd_sysvar_slot_hashes_footprint( FD_SYSVAR_SLOT_HASHES_CAP ) ); - fd_slot_hash_t * shnull = NULL; - fd_slot_hashes_global_t * slot_hashes_global = fd_sysvar_slot_hashes_join( fd_sysvar_slot_hashes_new( mem, FD_SYSVAR_SLOT_HASHES_CAP ), &shnull ); +fd_sysvar_slot_hashes_update( fd_exec_slot_ctx_t * slot_ctx ) { - fd_sysvar_slot_hashes_write( slot_ctx, slot_hashes_global); - fd_sysvar_slot_hashes_delete( fd_sysvar_slot_hashes_leave( slot_hashes_global, shnull ) ); - } FD_SPAD_FRAME_END; -} + /* Create an empty sysvar account if it doesn't exist + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2295 */ -/* https://github.com/anza-xyz/agave/blob/b11ca828cfc658b93cb86a6c5c70561875abe237/runtime/src/bank.rs#L2283-L2294 */ -void -fd_sysvar_slot_hashes_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { -FD_SPAD_FRAME_BEGIN( runtime_spad ) { - fd_slot_hashes_global_t * slot_hashes_global = fd_sysvar_slot_hashes_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); - fd_slot_hash_t * hashes = NULL; - if( FD_UNLIKELY( !slot_hashes_global ) ) { - /* Note: Agave's implementation initializes a new slot_hashes if it doesn't already exist (refer to above URL). */ - void * mem = fd_spad_alloc( runtime_spad, FD_SYSVAR_SLOT_HASHES_ALIGN, fd_sysvar_slot_hashes_footprint( FD_SYSVAR_SLOT_HASHES_CAP ) ); - slot_hashes_global = fd_sysvar_slot_hashes_new( mem, FD_SYSVAR_SLOT_HASHES_CAP ); + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !FD_SYSVAR_CACHE_EXISTS( sysvar_cache, slot_hashes ) ) ) { + fd_sysvar_slot_hashes_init( slot_ctx ); } - slot_hashes_global = fd_sysvar_slot_hashes_join( slot_hashes_global, &hashes ); + + /* Update an existing sysvar account, but abort if deserialization of + that existing account failed. + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2294 */ + + fd_slot_hash_t * hashes = fd_sysvar_slot_hashes_join( sysvar_cache ); + if( FD_UNLIKELY( !hashes ) ) FD_LOG_ERR(( "Slot hashes sysvar is invalid, cannot update" )); uchar found = 0; for( deq_fd_slot_hash_t_iter_t iter = deq_fd_slot_hash_t_iter_init( hashes ); @@ -123,51 +52,12 @@ FD_SPAD_FRAME_BEGIN( runtime_spad ) { }; FD_LOG_DEBUG(( "fd_sysvar_slot_hash_update: slot %lu, hash %s", slot_hash.slot, FD_BASE58_ENC_32_ALLOCA( slot_hash.hash.key ) )); - if( deq_fd_slot_hash_t_full( hashes ) ) + if( deq_fd_slot_hash_t_full( hashes ) ) { memset( deq_fd_slot_hash_t_pop_tail_nocopy( hashes ), 0, sizeof(fd_slot_hash_t) ); + } deq_fd_slot_hash_t_push_head( hashes, slot_hash ); } - fd_sysvar_slot_hashes_write( slot_ctx, slot_hashes_global ); - fd_sysvar_slot_hashes_leave( slot_hashes_global, hashes ); -} FD_SPAD_FRAME_END; -} - -fd_slot_hashes_global_t * -fd_sysvar_slot_hashes_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( rec ); - int err = fd_txn_account_init_from_funk_readonly( rec, (fd_pubkey_t const *)&fd_sysvar_slot_hashes_id, funk, funk_txn ); - if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) { - return NULL; - } - - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( rec->vt->get_lamports( rec )==0 ) ) { - return NULL; - } - - fd_bincode_decode_ctx_t decode = { - .data = rec->vt->get_data( rec ), - .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec ) - }; - - ulong total_sz = 0UL; - err = fd_slot_hashes_decode_footprint( &decode, &total_sz ); - if( FD_UNLIKELY( err ) ) { - return NULL; - } - - uchar * mem = fd_spad_alloc( spad, fd_slot_hashes_align(), total_sz ); - - if( FD_UNLIKELY( !mem ) ) { - FD_LOG_ERR(( "Unable to allocate memory for slot hashes" )); - } - - return fd_slot_hashes_decode_global( mem, &decode ); + fd_sysvar_slot_hashes_leave( sysvar_cache, hashes ); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.h b/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.h index a48a8c5203..4da90a780f 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.h @@ -1,62 +1,41 @@ -#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_slot_hashes_h -#define HEADER_fd_src_flamenco_runtime_sysvar_fd_slot_hashes_h +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_slot_hashes_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_slot_hashes_h + +/* fd_sysvar_slot_hashes.h manages the "slot hashes" sysvar account + (address SysvarS1otHashes111111111111111111111111111). + + This sysvar contains bank hashes of previous slots. */ -#include "../../../funk/fd_funk.h" -#include "../../../funk/fd_funk_txn.h" #include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" -/* The slot hashes sysvar contains the most recent hashes of the slot's parent bank hashes. */ /* FD_SYSVAR_SLOT_HASHES_CAP is the max number of entries that the "slot hashes" sysvar will include. - https://github.com/anza-xyz/agave/blob/6398ddf6ab8a8f81017bf675ab315a70067f0bf0/sdk/program/src/slot_hashes.rs#L19 */ - -#define FD_SYSVAR_SLOT_HASHES_CAP (512UL) -#define FD_SYSVAR_SLOT_HASHES_ALIGN (FD_SLOT_HASHES_GLOBAL_ALIGN) - -FD_PROTOTYPES_BEGIN + https://docs.rs/solana-slot-hashes/2.2.1/src/solana_slot_hashes/lib.rs.html#21 */ +#define FD_SYSVAR_SLOT_HASHES_CAP (512UL) -ulong -fd_sysvar_slot_hashes_footprint( ulong slot_hashes_cap ); +/* FD_SYSVAR_SLOT_HASHES_BINCODE_SZ is the serialized size of the slot + hashes sysvar account. (static/hardcoded) -void * -fd_sysvar_slot_hashes_new( void * mem, - ulong slot_hashes_cap ); + Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/slot_hashes.rs#L69 */ -fd_slot_hashes_global_t * -fd_sysvar_slot_hashes_join( void * shmem, - fd_slot_hash_t ** slot_hash ); +#define FD_SYSVAR_SLOT_HASHES_BINCODE_SZ (20488UL) -void * -fd_sysvar_slot_hashes_leave( fd_slot_hashes_global_t * slot_hashes_global, - fd_slot_hash_t * slot_hash ); +FD_PROTOTYPES_BEGIN -void * -fd_sysvar_slot_hashes_delete( void * mem ); +/* fd_sysvar_slot_hashes_init creates a "slot hashes" sysvar account + (overwrites an existing one). */ -/* Write a funk entry for the slot hashes sysvar account (exposed for tests) */ void -fd_sysvar_slot_hashes_write( fd_exec_slot_ctx_t * slot_ctx, - fd_slot_hashes_global_t * slot_hashes_global ); +fd_sysvar_slot_hashes_init( fd_exec_slot_ctx_t * slot_ctx ); -void -fd_sysvar_slot_hashes_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ); +/* fd_sysvar_slot_hashes_update updates the "slot hashes" sysvar account + at the start of a block. */ -/* Update the slot hashes sysvar account. This should be called at the end of every slot, before execution commences. */ void -fd_sysvar_slot_hashes_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ); - -/* fd_sysvar_slot_hashes_read reads the slot hashes sysvar from funk. - If the account doesn't exist in funk or if the account has zero - lamports, this function returns NULL. */ -fd_slot_hashes_global_t * -fd_sysvar_slot_hashes_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); +fd_sysvar_slot_hashes_update( fd_exec_slot_ctx_t * slot_ctx ); FD_PROTOTYPES_END -#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_slot_hashes_h */ +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_slot_hashes_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.c b/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.c index a0d9628e0d..8a6e47a8d7 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.c @@ -1,209 +1,137 @@ #include "fd_sysvar_slot_history.h" -#include "fd_sysvar.h" -#include "fd_sysvar_rent.h" -#include "../fd_executor_err.h" +#include "fd_sysvar_cache.h" +#include "../context/fd_exec_slot_ctx.h" #include "../fd_system_ids.h" -/* FIXME These constants should be header defines */ - -static const ulong slot_history_min_account_size = 131097; - -/* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L37 */ -static const ulong slot_history_max_entries = 1024 * 1024; - /* TODO: move into separate bitvec library */ -static const ulong bits_per_block = 8 * sizeof(ulong); +#define BITS_PER_BLOCK 64 -void -fd_sysvar_slot_history_set( fd_slot_history_global_t * history, - ulong i ) { - if( FD_UNLIKELY( i > history->next_slot && i - history->next_slot >= slot_history_max_entries ) ) { - FD_LOG_WARNING(( "Ignoring out of bounds (i=%lu next_slot=%lu)", i, history->next_slot )); - return; - } +#define FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT ( FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES / BITS_PER_BLOCK ) - ulong * blocks = (ulong *)((uchar*)history + history->bits_bitvec_offset); - ulong blocks_len = history->bits_bitvec_len; +static ulong * +bitvec_blocks( fd_slot_history_global_t * history ) { + FD_TEST( history->has_bits && history->bits_bitvec_len == FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT ); + return (ulong *)( (uchar *)history + history->bits_bitvec_offset ); +} - // Skipped slots, delete them from history - if( FD_UNLIKELY( blocks_len == 0 ) ) return; - for( ulong j = history->next_slot; j < i; j++ ) { - ulong block_idx = (j / bits_per_block) % (blocks_len); - blocks[ block_idx ] &= ~( 1UL << ( j % bits_per_block ) ); - } - ulong block_idx = (i / bits_per_block) % (blocks_len); - blocks[ block_idx ] |= ( 1UL << ( i % bits_per_block ) ); +/* See bv::BitVec::set */ + +static void +bitvec_remove( fd_slot_history_global_t * history, + ulong slot ) { + FD_TEST( history->has_bits && slot < history->bits_len ); + ulong * blocks = bitvec_blocks( history ); + ulong key = slot / BITS_PER_BLOCK; + ulong idx = slot % BITS_PER_BLOCK; + blocks[ key ] &= ~( 1UL << idx ); } -FD_FN_UNUSED static const ulong blocks_len = slot_history_max_entries / bits_per_block; - -int -fd_sysvar_slot_history_write_history( fd_exec_slot_ctx_t * slot_ctx, - fd_slot_history_global_t * history ) { - ulong sz = slot_history_min_account_size; - uchar enc[ sz ]; - fd_memset( enc, 0, sz ); - fd_bincode_encode_ctx_t ctx; - ctx.data = enc; - ctx.dataend = enc + sz; - int err = fd_slot_history_encode_global( history, &ctx ); - if (0 != err) - return err; - return fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_slot_history_id, enc, sz, fd_bank_slot_get( slot_ctx->bank ) ); +static void +bitvec_insert( fd_slot_history_global_t * history, + ulong slot ) { + FD_TEST( history->has_bits && slot < history->bits_len ); + ulong * blocks = bitvec_blocks( history ); + ulong key = slot / BITS_PER_BLOCK; + ulong idx = slot % BITS_PER_BLOCK; + blocks[ key ] |= 1UL<next_slot = fd_bank_slot_get( slot_ctx->bank ) + 1UL; - history->bits_bitvec_offset = (ulong)((uchar*)blocks - (uchar*)history); - history->bits_len = slot_history_max_entries; - history->bits_bitvec_len = blocks_len; - history->has_bits = 1; - memset( blocks, 0, sizeof(ulong) * blocks_len ); - - /* TODO: handle slot != 0 init case */ - fd_sysvar_slot_history_set( history, fd_bank_slot_get( slot_ctx->bank ) ); - fd_sysvar_slot_history_write_history( slot_ctx, history ); - } FD_SPAD_FRAME_END; -} +fd_sysvar_slot_history_add( fd_slot_history_global_t * history, + ulong slot ) { -/* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/runtime/src/bank.rs#L2345 */ -int -fd_sysvar_slot_history_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ) { - /* Set current_slot, and update next_slot */ + /* Sanity checks: This sysvar's dimensions are hardcoded */ + FD_TEST( history->has_bits && + history->bits_bitvec_len == FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT && + history->bits_len == FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES ); - fd_pubkey_t const * key = &fd_sysvar_slot_history_id; + /* https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L63 */ + if( slot > history->next_slot && slot - history->next_slot >= FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES ) { - FD_TXN_ACCOUNT_DECL( rec ); - int err = fd_txn_account_init_from_funk_readonly( rec, key, slot_ctx->funk, slot_ctx->funk_txn ); - if (err) - FD_LOG_CRIT(( "fd_txn_account_init_from_funk_readonly(slot_history) failed: %d", err )); + /* https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L64-L69 */ + fd_memset( bitvec_blocks( history ), 0, sizeof(ulong) * FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT ); - fd_bincode_decode_ctx_t ctx = { - .data = rec->vt->get_data( rec ), - .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec ) - }; + } else { - ulong total_sz = 0UL; - err = fd_slot_history_decode_footprint( &ctx, &total_sz ); - if( FD_UNLIKELY( err ) ) { - FD_LOG_CRIT(( "fd_slot_history_decode_footprint failed %d", err )); - } + /* https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L71-L73 + Obviously, there's room for optimization here, see src/util/tmpl/fd_set_dynamic.c */ + for( ulong i=history->next_slot; inext_slot = slot + 1UL; - /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_history.rs#L48 */ - fd_sysvar_slot_history_set( history, fd_bank_slot_get( slot_ctx->bank ) ); - history->next_slot = fd_bank_slot_get( slot_ctx->bank ) + 1; - - ulong sz = slot_history_min_account_size; - - err = fd_txn_account_init_from_funk_mutable( rec, key, slot_ctx->funk, slot_ctx->funk_txn, 1, sz ); - if (err) - FD_LOG_CRIT(( "fd_txn_account_init_from_funk_mutable(slot_history) failed: %d", err )); +} - fd_bincode_encode_ctx_t e_ctx = { - .data = rec->vt->get_data_mut( rec ), - .dataend = rec->vt->get_data_mut( rec )+sz, - }; +/* See solana_slot_history::SlotHistory::default + https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L29 */ - if( FD_UNLIKELY( fd_slot_history_encode_global( history, &e_ctx ) ) ) { - return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; - } +void +fd_sysvar_slot_history_init( fd_exec_slot_ctx_t * slot_ctx, + fd_spad_t * runtime_spad ) { + ulong sz_max = 0UL; + uchar * data = fd_sysvar_cache_data_modify_prepare( + slot_ctx, &fd_sysvar_slot_history_id, NULL, &sz_max ); + if( FD_UNLIKELY( !data ) ) FD_LOG_ERR(( "fd_sysvar_cache_data_modify_prepare(slot_history) failed" )); + FD_TEST( sz_max >= FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ ); + + /* Construct a position-independent slot history object */ + ulong block_cnt = FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT; + ulong total_sz = sizeof(fd_slot_history_global_t) + alignof(fd_slot_history_global_t) + + (sizeof(ulong) + alignof(ulong)) * block_cnt; - fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank ); - rec->vt->set_lamports( rec, fd_rent_exempt_minimum_balance( rent, sz ) ); + FD_SPAD_FRAME_BEGIN( runtime_spad ) { - rec->vt->set_data_len( rec, sz ); - rec->vt->set_owner( rec, &fd_sysvar_owner_id ); + uchar * mem = fd_spad_alloc_check( runtime_spad, alignof(fd_slot_history_global_t), total_sz ); + fd_slot_history_global_t * history = (fd_slot_history_global_t *)mem; + ulong * blocks = (ulong *)fd_ulong_align_up( (ulong)((uchar*)history + sizeof(fd_slot_history_global_t)), alignof(ulong) ); - fd_txn_account_mutable_fini( rec, slot_ctx->funk, slot_ctx->funk_txn ); + history->next_slot = fd_bank_slot_get( slot_ctx->bank ) + 1UL; + history->bits_bitvec_offset = (ulong)((uchar*)blocks - (uchar*)history); + history->bits_len = FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES; + history->bits_bitvec_len = FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT; + history->has_bits = 1; + memset( blocks, 0, sizeof(ulong) * FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT ); - return 0; + } FD_SPAD_FRAME_END; } -fd_slot_history_global_t * -fd_sysvar_slot_history_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - - /* Set current_slot, and update next_slot */ - - fd_pubkey_t const * key = &fd_sysvar_slot_history_id; +/* See solana_runtime::bank::Bank::update_slot_history + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2276 */ - FD_TXN_ACCOUNT_DECL( rec ); - int err = fd_txn_account_init_from_funk_readonly( rec, key, funk, funk_txn ); - if( err ) { - FD_LOG_CRIT(( "fd_txn_account_init_from_funk_readonly(slot_history) failed: %d", err )); +void +fd_sysvar_slot_history_update( fd_exec_slot_ctx_t * slot_ctx, + fd_spad_t * runtime_spad ) { + /* Create an empty sysvar account if it doesn't exist + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2281 */ + + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_cache_flags_exists( sysvar_cache->desc.slot_history.flags ) ) ) { + fd_sysvar_slot_history_init( slot_ctx, runtime_spad ); } - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( rec->vt->get_lamports( rec ) == 0UL ) ) { - return NULL; - } + /* Update an existing sysvar account, but abort if deserialization of + that existing account failed. + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2280 */ - fd_bincode_decode_ctx_t ctx = { - .data = rec->vt->get_data( rec ), - .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec ) - }; + fd_slot_history_global_t * history = fd_sysvar_slot_history_join( sysvar_cache ); + if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "Slot history sysvar is invalid, cannot update" )); - ulong total_sz = 0UL; - err = fd_slot_history_decode_footprint( &ctx, &total_sz ); - if( err ) { - FD_LOG_ERR(( "fd_slot_history_decode_footprint failed" )); - } + /* Advance to current slot, set this slot's bit. + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2282 */ - uchar * mem = fd_spad_alloc( spad, fd_slot_history_align(), total_sz ); - if( !mem ) { - FD_LOG_ERR(( "Unable to allocate memory for slot history" )); - } - - return fd_slot_history_decode_global( mem, &ctx ); -} - -int -fd_sysvar_slot_history_find_slot( fd_slot_history_global_t const * history, - ulong slot, - fd_wksp_t * wksp ) { - (void)wksp; - ulong * blocks = (ulong *)((uchar*)history + history->bits_bitvec_offset); - if( FD_UNLIKELY( !blocks ) ) { - FD_LOG_ERR(( "Unable to find slot history blocks" )); - } - ulong blocks_len = history->bits_bitvec_len; + fd_sysvar_slot_history_add( history, fd_bank_slot_get( slot_ctx->bank ) ); + /* Persist write */ - if( slot > history->next_slot - 1UL ) { - return FD_SLOT_HISTORY_SLOT_FUTURE; - } else if ( slot < fd_ulong_sat_sub( history->next_slot, slot_history_max_entries ) ) { - return FD_SLOT_HISTORY_SLOT_TOO_OLD; - } else { - ulong block_idx = (slot / bits_per_block) % blocks_len; - if( blocks[ block_idx ] & ( 1UL << ( slot % bits_per_block ) ) ) { - return FD_SLOT_HISTORY_SLOT_FOUND; - } else { - return FD_SLOT_HISTORY_SLOT_NOT_FOUND; - } - } + fd_sysvar_slot_history_leave( sysvar_cache, history ); } + +#undef BITS_PER_BLOCK diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.h b/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.h index b49fefb06e..6c0fa4846e 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.h @@ -1,38 +1,77 @@ -#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_slot_history_h -#define HEADER_fd_src_flamenco_runtime_sysvar_fd_slot_history_h +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_slot_history_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_slot_history_h + +/* fd_sysvar_slot_history.h manages the "slot history" sysvar account + (address SysvarS1otHistory11111111111111111111111111). + + This sysvar is a ring buffer of bits indicating which slots contained + blocks. Slots without blocks are called "skipped slots". Updated + during "slot freeze" (at the end of a slot). */ #include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" -#include "../context/fd_exec_slot_ctx.h" -#define FD_SLOT_HISTORY_SLOT_FOUND (0) -#define FD_SLOT_HISTORY_SLOT_FUTURE (-1) -#define FD_SLOT_HISTORY_SLOT_NOT_FOUND (-2) -#define FD_SLOT_HISTORY_SLOT_TOO_OLD (-3) +/* Forward declaration */ +typedef struct fd_slot_history_global fd_slot_history_global_t; + +/* FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES specifies the number of bits + tracked by a slot history sysvar account. (static/hardcoded) + + Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L51 */ + +#define FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES 1048576UL + +/* FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ is the serialized size of the slot + history sysvar account. (static/hardcoded) + + Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/slot_history.rs#L65 */ + +#define FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ 131097UL + +/* Slot Freeze ********************************************************/ -/* The slot history sysvar contains a bit-vector indicating which slots have been processed in the current epoch. */ +/* fd_sysvar_slot_history_init creates a "slot history" sysvar account + (overwrites an existing one). Formats the slot history sysvar to + have a bit vector with FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES bits all + set to zero. The "next slot" field is set to one. + + Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L29 */ -/* Initialize the slot history sysvar account. */ void fd_sysvar_slot_history_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ); + fd_spad_t * spad ); + +/* fd_sysvar_slot_history_update updates the "slot history" sysvar after + processing a block. Called during "slot freeze". Does not run for + skipped slots. + + Has the following behavior: + - Account does not exist + => account is created (see fd_sysvar_slot_history_init) + - Account exists, deserialize fails + => process is terminated with FD_LOG_ERR + - Account exists, deserialize succeeds + => advance ring buffer, clear bits of evicted slots + => set bit for current slot + => set "next slot" field to current slot + 1 + + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2276 */ -/* Update the slot history sysvar account. This should be called at the end of every slot, after execution has concluded. */ -int +void fd_sysvar_slot_history_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runtime_spad ); -/* fd_sysvar_slot_history_read reads the slot history sysvar from funk. - If the account doesn't exist in funk or if the account has zero - lamports, this function returns NULL. */ +/* Ring buffer API ****************************************************/ + +/* fd_sysvar_slot_history_add sets the bit for the given slot number. + If the slot number exceeds the current slot range of the sysvar's + ring buffer, the ring buffer is advanced, and old bits are evicted. -fd_slot_history_global_t * -fd_sysvar_slot_history_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); + This function has a bug where an arbitrary other slot's bit is set if + the given slot number is below the ring buffer's window. Firedancer + reproduces this bug since this is consensus-enshrined logic. */ + +void +fd_sysvar_slot_history_add( fd_slot_history_global_t * history, + ulong slot ); -int -fd_sysvar_slot_history_find_slot( fd_slot_history_global_t const * history, - ulong slot, - fd_wksp_t * wksp ); -#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_slot_history_h */ +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_slot_history_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c index 5c705c7a85..fa237ea20a 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c @@ -1,64 +1,39 @@ #include "fd_sysvar_stake_history.h" -#include "fd_sysvar.h" #include "../fd_system_ids.h" -#include "../context/fd_exec_slot_ctx.h" +#include "fd_sysvar_epoch_schedule.h" -/* Ensure that the size declared by our header matches the minimum size - of the corresponding fd_types entry. */ +void +fd_sysvar_stake_history_init( fd_exec_slot_ctx_t * slot_ctx ) { + ulong sz_max; + uchar * data = fd_sysvar_cache_data_modify_prepare( slot_ctx, &fd_sysvar_stake_history_id, NULL, &sz_max ); + FD_TEST( sz_max>=FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ); + fd_memset( data, 0, FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ); + fd_sysvar_cache_data_modify_commit( slot_ctx, &fd_sysvar_stake_history_id, FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ); -static void -write_stake_history( fd_exec_slot_ctx_t * slot_ctx, - fd_stake_history_t * stake_history ) { - /* https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/sysvar/stake_history.rs#L12 */ - uchar enc[16392] = {0}; +} - fd_bincode_encode_ctx_t encode = - { .data = enc, - .dataend = enc + sizeof(enc) }; - if( FD_UNLIKELY( fd_stake_history_encode( stake_history, &encode )!=FD_BINCODE_SUCCESS ) ) - FD_LOG_ERR(("fd_stake_history_encode failed")); +/* https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2365 */ - fd_sysvar_set( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &fd_sysvar_owner_id, &fd_sysvar_stake_history_id, enc, sizeof(enc), fd_bank_slot_get( slot_ctx->bank ) ); -} +void +fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, + fd_epoch_stake_history_entry_pair_t const * entry ) { -fd_stake_history_t * -fd_sysvar_stake_history_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ) { - FD_TXN_ACCOUNT_DECL( stake_rec ); - int err = fd_txn_account_init_from_funk_readonly( stake_rec, &fd_sysvar_stake_history_id, funk, funk_txn ); - if( FD_UNLIKELY( err!=FD_ACC_MGR_SUCCESS ) ) { - return NULL; - } + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( sysvar_cache ); - /* This check is needed as a quirk of the fuzzer. If a sysvar account - exists in the accounts database, but doesn't have any lamports, - this means that the account does not exist. This wouldn't happen - in a real execution environment. */ - if( FD_UNLIKELY( stake_rec->vt->get_lamports( stake_rec )==0 ) ) { - return NULL; - } + ulong const prev_slot = fd_bank_parent_slot_get( slot_ctx->bank ); + ulong const cur_slot = fd_bank_slot_get( slot_ctx->bank ); + ulong const prev_epoch = fd_slot_to_epoch( &epoch_schedule, prev_slot, NULL ); + ulong const cur_epoch = fd_slot_to_epoch( &epoch_schedule, cur_slot, NULL ); - return fd_bincode_decode_spad( - stake_history, spad, - stake_rec->vt->get_data( stake_rec ), - stake_rec->vt->get_data_len( stake_rec ), - &err ); -} + if( FD_LIKELY( prev_epoch==cur_epoch ) ) return; -void -fd_sysvar_stake_history_init( fd_exec_slot_ctx_t * slot_ctx ) { - fd_stake_history_t stake_history; - fd_stake_history_new( &stake_history ); - write_stake_history( slot_ctx, &stake_history ); -} + if( FD_UNLIKELY( !FD_SYSVAR_CACHE_EXISTS( sysvar_cache, stake_history ) ) ) { + fd_sysvar_stake_history_init( slot_ctx ); + } -void -fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, - fd_epoch_stake_history_entry_pair_t * pair, - fd_spad_t * runtime_spad ) { - // Need to make this maybe zero copies of map... - fd_stake_history_t * stake_history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); + fd_stake_history_t * stake_history = fd_sysvar_stake_history_join( sysvar_cache ); + if( FD_UNLIKELY( !stake_history ) ) FD_LOG_ERR(( "Stake history sysvar is invalid, cannot update" )); if( stake_history->fd_stake_history_offset == 0 ) { stake_history->fd_stake_history_offset = stake_history->fd_stake_history_size - 1; @@ -71,12 +46,10 @@ fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, } // This should be done with a bit mask + // (FIXME what did Josh mean with this comment) ulong idx = stake_history->fd_stake_history_offset; - stake_history->fd_stake_history[ idx ].epoch = pair->epoch; - stake_history->fd_stake_history[ idx ].entry.activating = pair->entry.activating; - stake_history->fd_stake_history[ idx ].entry.effective = pair->entry.effective; - stake_history->fd_stake_history[ idx ].entry.deactivating = pair->entry.deactivating; + stake_history->fd_stake_history[ idx ] = *entry; - write_stake_history( slot_ctx, stake_history ); + fd_sysvar_stake_history_leave( sysvar_cache, stake_history ); } diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.h b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.h index 67dbb36da7..e7ab0418aa 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.h @@ -1,40 +1,50 @@ -#ifndef HEADER_fd_src_flamenco_runtime_fd_sysvar_stake_history_h -#define HEADER_fd_src_flamenco_runtime_fd_sysvar_stake_history_h +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_stake_history_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_stake_history_h + +/* fd_sysvar_stake_history.h manages the "stake history" sysvar account + (address SysvarStakeHistory1111111111111111111111111). It tracks the + staked SOL capitalization per epoch. Updated during "bank creation" + (at the start of a slot). */ #include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" -#include "../../../funk/fd_funk.h" + +/* Forward declaration */ +typedef struct fd_epoch_stake_history_entry_pair fd_epoch_stake_history_entry_pair_t; /* FD_SYSVAR_STAKE_HISTORY_CAP is the max number of entries that the "stake history" sysvar will include. - https://github.com/anza-xyz/agave/blob/6398ddf6ab8a8f81017bf675ab315a70067f0bf0/sdk/program/src/stake_history.rs#L12 */ + https://github.com/solana-program/stake/blob/main/interface/src/stake_history.rs#L8 */ #define FD_SYSVAR_STAKE_HISTORY_CAP (512UL) +/* FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ is the serialized size of the + stake history sysvar account. (static/hardcoded) + + Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/stake_history.rs#L66 */ + +#define FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ (16392UL) + FD_PROTOTYPES_BEGIN -/* The stake history sysvar contains the history of cluster-wide activations and de-activations per-epoch. Updated at the start of each epoch. */ +/* fd_sysvar_stake_history_init sets the "stake history" sysvar account + to an empty vector. This is used to initialize the runtime from + genesis (FIXME Agave reference). */ -/* Initialize the stake history sysvar account. */ void fd_sysvar_stake_history_init( fd_exec_slot_ctx_t * slot_ctx ); -/* fd_sysvar_stake_history_read reads the stake history sysvar from funk. - If the account doesn't exist in funk or if the account has zero - lamports, this function returns NULL. */ +/* fd_sysvar_stake_history_update appends an entry to the "stake + history" sysvar account. Called during the epoch boundary (at the + start of the first slot of an epoch). -fd_stake_history_t * -fd_sysvar_stake_history_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); + FIXME Clarify when this sysvar is set if the first slot of an epoch + is skipped. */ -/* Update the stake history sysvar account - called during epoch boundary */ void -fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, - fd_epoch_stake_history_entry_pair_t * pair, - fd_spad_t * runtime_spad ); +fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, + fd_epoch_stake_history_entry_pair_t const * entry ); FD_PROTOTYPES_END -#endif /* HEADER_fd_src_flamenco_runtime_fd_sysvar_stake_history_h */ +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_stake_history_h */ diff --git a/src/flamenco/runtime/sysvar/test_sysvar.c b/src/flamenco/runtime/sysvar/test_sysvar.c new file mode 100644 index 0000000000..f1b9000819 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar.c @@ -0,0 +1,20 @@ +#include "test_sysvar_cache.c" +#include "test_sysvar_epoch_schedule.c" +#include "test_sysvar_rent.c" +#include "test_sysvar_slot_history.c" +#include "../../../util/fd_util.h" + +int +main( int argc, + char ** argv ) { + fd_boot( &argc, &argv ); + + test_sysvar_cache(); + test_sysvar_epoch_schedule(); + test_sysvar_rent(); + test_sysvar_slot_history(); + + FD_LOG_NOTICE(( "pass" )); + fd_halt(); + return 0; +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_cache.c b/src/flamenco/runtime/sysvar/test_sysvar_cache.c new file mode 100644 index 0000000000..f5e9100a9b --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_cache.c @@ -0,0 +1,4 @@ +void +test_sysvar_cache( void ) { + +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c b/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c index 6514e261ff..ecc5581966 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c @@ -94,11 +94,8 @@ test_epoch_schedule( fd_epoch_schedule_t const * t ) { } } -int -main( int argc, - char ** argv ) { - fd_boot( &argc, &argv ); - +void +test_sysvar_epoch_schedule( void ) { for( fd_epoch_schedule_t const * vec = fd_epoch_schedule_test_vectors; vec->slots_per_epoch; vec++ ) { @@ -106,8 +103,4 @@ main( int argc, test_epoch_schedule ( vec ); } - - FD_LOG_NOTICE(( "pass" )); - fd_halt(); - return 0; } diff --git a/src/flamenco/runtime/sysvar/test_sysvar_rent.c b/src/flamenco/runtime/sysvar/test_sysvar_rent.c index 6fb0807e0a..daa3e0560c 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_rent.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_rent.c @@ -40,12 +40,8 @@ test_rent_exempt_vector[] = { }; #define test_rent_exempt_vector_end (fd_rent_exempt_fixture_t const *)( (uchar const *)test_rent_exempt_vector + sizeof(test_rent_exempt_vector) ) - -int -main( int argc, - char ** argv ) { - fd_boot( &argc, &argv ); - +void +test_sysvar_rent( void ) { fd_rent_exempt_fixture_t const * iter; for( iter = test_rent_exempt_vector; iter < test_rent_exempt_vector_end; @@ -57,8 +53,4 @@ main( int argc, ulong min_balance = fd_rent_exempt_minimum_balance( &rent, iter->data_len ); FD_TEST( min_balance == iter->min_balance ); } - - FD_LOG_NOTICE(( "pass" )); - fd_halt(); - return 0; } diff --git a/src/flamenco/runtime/sysvar/test_sysvar_slot_history.c b/src/flamenco/runtime/sysvar/test_sysvar_slot_history.c new file mode 100644 index 0000000000..37b235487f --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_slot_history.c @@ -0,0 +1,6 @@ + +static void +test_sysvar_slot_history( void ) { + + +} diff --git a/src/flamenco/runtime/test_bank.c b/src/flamenco/runtime/test_bank.c index 3bcace1e5d..20d80e2ecd 100644 --- a/src/flamenco/runtime/test_bank.c +++ b/src/flamenco/runtime/test_bank.c @@ -81,7 +81,7 @@ main( int argc, char ** argv ) { fd_bank_t const * new_root = fd_banks_publish( banks, 7UL ); FD_TEST( new_root ); - FD_TEST( new_root->slot == 7UL ); + FD_TEST( new_root->slot_ == 7UL ); FD_TEST( new_root == bank7); fd_bank_t * bank10 = fd_banks_clone_from_parent( banks, 10UL, 7UL ); diff --git a/src/flamenco/runtime/test_blockhashes.c b/src/flamenco/runtime/test_blockhashes.c new file mode 100644 index 0000000000..a114589d9d --- /dev/null +++ b/src/flamenco/runtime/test_blockhashes.c @@ -0,0 +1,13 @@ +#include "fd_blockhashes.h" + +int +main( int argc, + char ** argv ) { + fd_boot( &argc, &argv ); + + FD_TEST( fd_blockhash_map_footprint( FD_BLOCKHASH_MAP_CHAIN_MAX )==FD_BLOCKHASH_MAP_FOOTPRINT ); + FD_LOG_NOTICE(( "%lu", fd_blockhash_map_footprint( FD_BLOCKHASH_MAP_FOOTPRINT ) )); + + fd_halt(); + return 0; +} diff --git a/src/flamenco/runtime/tests/fd_dump_pb.c b/src/flamenco/runtime/tests/fd_dump_pb.c index 2d46607c94..928f9815e7 100644 --- a/src/flamenco/runtime/tests/fd_dump_pb.c +++ b/src/flamenco/runtime/tests/fd_dump_pb.c @@ -363,32 +363,28 @@ dump_sanitized_transaction( fd_funk_t * funk, /** BLOCKHASH QUEUE DUMPING **/ static void -dump_blockhash_queue( fd_block_hash_queue_global_t const * queue, - fd_spad_t * spad, - pb_bytes_array_t ** output_blockhash_queue, - pb_size_t * output_blockhash_queue_count ) { +dump_blockhash_queue( fd_blockhashes_t const * queue, + fd_spad_t * spad, + pb_bytes_array_t ** output_blockhash_queue, + pb_size_t * output_blockhash_queue_count ) { pb_size_t cnt = 0; - fd_hash_hash_age_pair_t_mapnode_t * nn; - - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_block_hash_queue_ages_pool_join( queue ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = fd_block_hash_queue_ages_root_join( queue ); // Iterate over all block hashes in the queue and save them in the output - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( ages_pool, ages_root ); n; n = nn ) { - nn = fd_hash_hash_age_pair_t_map_successor( ages_pool, n ); - + ulong queue_index = 0UL; + for( fd_blockhash_deq_iter_t iter = fd_blockhash_deq_iter_init_rev( queue->d.deque ); + !fd_blockhash_deq_iter_done( queue->d.deque, iter ); + iter = fd_blockhash_deq_iter_prev( queue->d.deque, iter ) ) { /* Get the index in the blockhash queue - Lower index = newer - 0 will be the most recent blockhash - Index range is [0, max_age] (not a typo) */ - ulong queue_index = queue->last_hash_index - n->elem.val.hash_index; - fd_hash_t blockhash = n->elem.key; + fd_hash_t blockhash = fd_blockhash_deq_iter_ele_const( queue->d.deque, iter )->hash; // Write the blockhash to the correct index (note we write in reverse order since in the Protobuf message, the oldest blockhash goes first) pb_bytes_array_t * output_blockhash = fd_spad_alloc( spad, alignof(pb_bytes_array_t), PB_BYTES_ARRAY_T_ALLOCSIZE(sizeof(fd_hash_t)) ); output_blockhash->size = sizeof(fd_hash_t); fd_memcpy( output_blockhash->bytes, &blockhash, sizeof(fd_hash_t) ); - output_blockhash_queue[FD_BLOCKHASH_QUEUE_MAX_ENTRIES - queue_index] = output_blockhash; + output_blockhash_queue[FD_BLOCKHASH_QUEUE_MAX_ENTRIES - queue_index++] = output_blockhash; cnt++; } @@ -511,8 +507,11 @@ create_block_context_protobuf_from_block( fd_exec_test_block_context_t * block_c PB_BYTES_ARRAY_T_ALLOCSIZE((FD_BLOCKHASH_QUEUE_MAX_ENTRIES + 1) * sizeof(pb_bytes_array_t *)) ); block_context->blockhash_queue = output_blockhash_queue; - fd_block_hash_queue_global_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank ); - dump_blockhash_queue( bhq, spad, block_context->blockhash_queue, &block_context->blockhash_queue_count ); + dump_blockhash_queue( + fd_bank_block_hash_queue_query( slot_ctx->bank ), + spad, + block_context->blockhash_queue, + &block_context->blockhash_queue_count ); /* BlockContext -> SlotContext */ block_context->has_slot_ctx = true; @@ -853,12 +852,11 @@ create_txn_context_protobuf_from_txn( fd_exec_test_txn_context_t * txn_context_m entries. We have this incorrect logic implemented in fd_sysvar_recent_hashes:register_blockhash and it's not a huge issue, but something to keep in mind. */ pb_bytes_array_t ** output_blockhash_queue = fd_spad_alloc( - spad, - alignof(pb_bytes_array_t *), - PB_BYTES_ARRAY_T_ALLOCSIZE((FD_BLOCKHASH_QUEUE_MAX_ENTRIES + 1) * sizeof(pb_bytes_array_t *)) ); + spad, + alignof(pb_bytes_array_t *), + PB_BYTES_ARRAY_T_ALLOCSIZE((FD_BLOCKHASH_QUEUE_MAX_ENTRIES + 1) * sizeof(pb_bytes_array_t *)) ); txn_context_msg->blockhash_queue = output_blockhash_queue; - fd_block_hash_queue_global_t * block_hash_queue = (fd_block_hash_queue_global_t *)&txn_ctx->bank->block_hash_queue[0]; - dump_blockhash_queue( block_hash_queue, spad, output_blockhash_queue, &txn_context_msg->blockhash_queue_count ); + dump_blockhash_queue( fd_bank_block_hash_queue_query( bank ), spad, output_blockhash_queue, &txn_context_msg->blockhash_queue_count ); /* Transaction Context -> epoch_ctx */ txn_context_msg->has_epoch_ctx = true; diff --git a/src/flamenco/runtime/tests/harness/fd_block_harness.c b/src/flamenco/runtime/tests/harness/fd_block_harness.c index 4c0839cd36..f832a71366 100644 --- a/src/flamenco/runtime/tests/harness/fd_block_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_block_harness.c @@ -226,9 +226,9 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Set up slot context */ ulong slot = test_ctx->slot_ctx.slot; - slot_ctx->funk_txn = funk_txn; - slot_ctx->funk = funk; - runner->bank->slot = slot; + slot_ctx->funk_txn = funk_txn; + slot_ctx->funk = funk; + runner->bank->slot_ = slot; fd_hash_t * bank_hash = fd_bank_bank_hash_modify( slot_ctx->bank ); fd_memcpy( bank_hash, test_ctx->slot_ctx.parent_bank_hash, sizeof(fd_hash_t) ); @@ -245,7 +245,7 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_clock_timestamp_votes_votes_root_update( clock_timestamp_votes, clock_root ); fd_bank_clock_timestamp_votes_end_locking_modify( slot_ctx->bank ); - slot_ctx->bank->slot = slot; + slot_ctx->bank->slot_ = slot; fd_bank_block_height_set( slot_ctx->bank, test_ctx->slot_ctx.block_height ); @@ -350,14 +350,10 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Add accounts to bpf program cache */ fd_bpf_scan_and_create_bpf_program_cache_entry( slot_ctx, runner->spad ); - /* Finish init epoch bank sysvars */ - fd_epoch_schedule_t * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad ); - fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule ); + fd_epoch_schedule_t const epoch_schedule = + fd_sysvar_epoch_schedule_read_nofail( slot_ctx->sysvar_cache ); - fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad ); - fd_bank_rent_set( slot_ctx->bank, *rent ); - - stakes->epoch = fd_slot_to_epoch( epoch_schedule, test_ctx->slot_ctx.prev_slot, NULL ); + stakes->epoch = fd_slot_to_epoch( &epoch_schedule, test_ctx->slot_ctx.prev_slot, NULL ); fd_bank_stakes_end_locking_modify( slot_ctx->bank ); @@ -395,21 +391,7 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_bank_epoch_stakes_end_locking_modify( slot_ctx->bank ); /* Update leader schedule */ - fd_runtime_update_leaders( slot_ctx->bank, fd_bank_slot_get( slot_ctx->bank ), runner->spad ); - - /* Initialize the blockhash queue and recent blockhashes sysvar from the input blockhash queue */ - fd_block_hash_queue_global_t * block_hash_queue = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0]; - uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)block_hash_queue + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) ); - uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, FD_BLOCKHASH_QUEUE_MAX_ENTRIES ) ); - - block_hash_queue->max_age = FD_BLOCKHASH_QUEUE_MAX_ENTRIES; // Max age is fixed at 300 - block_hash_queue->ages_root_offset = 0UL; - block_hash_queue->ages_pool_offset = (ulong)fd_hash_hash_age_pair_t_map_leave( ages_pool ) - (ulong)block_hash_queue; - block_hash_queue->last_hash_index = 0UL; - block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue; - - fd_memset( last_hash_mem, 0, sizeof(fd_hash_t) ); + fd_runtime_update_leaders( slot_ctx, fd_bank_slot_get( slot_ctx->bank ), runner->spad ); /* TODO: We might need to load this in from the input. We also need to size this out for worst case, but this also blows up the memory @@ -421,26 +403,14 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_memset( genesis_hash->hash, 0, sizeof(fd_hash_t) ); // Use the latest lamports per signature - fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad ); - fd_recent_block_hashes_t rbh[1]; - if( rbh_global ) { - rbh->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset ); - } - - if( rbh_global && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) { - fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh->hashes ); - if( last && last->fee_calculator.lamports_per_signature!=0UL ) { - fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature ); - fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature ); - } - } + /* FIXME set bank "lamports_per_signature" from blockhash queue */ // Populate blockhash queue and recent blockhashes sysvar for( ushort i=0; iblockhash_queue_count; ++i ) { fd_block_block_hash_entry_t blockhash_entry; memcpy( &blockhash_entry.blockhash, test_ctx->blockhash_queue[i]->bytes, sizeof(fd_hash_t) ); fd_bank_poh_set( slot_ctx->bank, blockhash_entry.blockhash ); - fd_sysvar_recent_hashes_update( slot_ctx, runner->spad ); + fd_sysvar_recent_hashes_update( slot_ctx ); } // Set the current poh from the input (we skip POH verification in this fuzzing target) diff --git a/src/flamenco/runtime/tests/harness/fd_elf_harness.c b/src/flamenco/runtime/tests/harness/fd_elf_harness.c index d71573d6cb..1fb08b0c5a 100644 --- a/src/flamenco/runtime/tests/harness/fd_elf_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_elf_harness.c @@ -1,4 +1,5 @@ #include "fd_elf_harness.h" +#include "../../../vm/fd_vm_base.h" ulong fd_runtime_fuzz_sbpf_load_run( fd_runtime_fuzz_runner_t * runner, diff --git a/src/flamenco/runtime/tests/harness/fd_elf_harness.h b/src/flamenco/runtime/tests/harness/fd_elf_harness.h index a382c03308..2eb142b1a0 100644 --- a/src/flamenco/runtime/tests/harness/fd_elf_harness.h +++ b/src/flamenco/runtime/tests/harness/fd_elf_harness.h @@ -3,8 +3,6 @@ #include "fd_harness_common.h" -#include "../../../vm/fd_vm_base.h" - #include "generated/elf.pb.h" FD_PROTOTYPES_BEGIN diff --git a/src/flamenco/runtime/tests/harness/fd_instr_harness.c b/src/flamenco/runtime/tests/harness/fd_instr_harness.c index bff8054719..829c084f31 100644 --- a/src/flamenco/runtime/tests/harness/fd_instr_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_instr_harness.c @@ -4,11 +4,6 @@ #include "fd_instr_harness.h" #include "../../fd_system_ids.h" -#include "../../sysvar/fd_sysvar_clock.h" -#include "../../sysvar/fd_sysvar_epoch_schedule.h" -#include "../../sysvar/fd_sysvar_recent_hashes.h" -#include "../../sysvar/fd_sysvar_last_restart_slot.h" -#include "../../sysvar/fd_sysvar_rent.h" int fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, @@ -44,15 +39,15 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Set up slot context */ - slot_ctx->funk_txn = funk_txn; - slot_ctx->funk = funk; + slot_ctx->funk_txn = funk_txn; + slot_ctx->funk = funk; /* Bank manager */ - slot_ctx->bank = runner->bank; - fd_bank_clear_bank( slot_ctx->bank ); + fd_bank_t * bank = slot_ctx->bank = runner->bank; + fd_bank_clear_bank( bank ); - fd_features_t * features = fd_bank_features_modify( slot_ctx->bank ); + fd_features_t * features = fd_bank_features_modify( bank ); fd_exec_test_feature_set_t const * feature_set = &test_ctx->epoch_context.features; if( !fd_runtime_fuzz_restore_features( features, feature_set ) ) { return 0; @@ -60,26 +55,14 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Set up epoch context. Defaults obtained from GenesisConfig::Default() */ - fd_rent_t * rent_bm = fd_bank_rent_modify( slot_ctx->bank ); - rent_bm->lamports_per_uint8_year = 3480; - rent_bm->exemption_threshold = 2; - rent_bm->burn_percent = 50; - - /* Blockhash queue init */ - - fd_block_hash_queue_global_t * block_hash_queue = fd_bank_block_hash_queue_modify( slot_ctx->bank ); - - uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)block_hash_queue + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) ); - uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 400 ) ); - - block_hash_queue->max_age = FD_BLOCKHASH_QUEUE_MAX_ENTRIES; - block_hash_queue->ages_root_offset = 0UL; - fd_block_hash_queue_ages_pool_update( block_hash_queue, ages_pool ); - block_hash_queue->last_hash_index = 0UL; - block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue; - - memset( last_hash_mem, 0, sizeof(fd_hash_t) ); + { + fd_rent_t const rent = { + .lamports_per_uint8_year = 3480, + .exemption_threshold = 2, + .burn_percent = 50 + }; + fd_sysvar_rent_write( slot_ctx, &rent ); + } /* Set up txn context */ @@ -217,100 +200,56 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Fill missing sysvar cache values with defaults */ /* We create mock accounts for each of the sysvars and hardcode the data fields before loading it into the account manager */ /* We use Agave sysvar defaults for data field values */ + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); /* Clock */ // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L466-L474 - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad ); - if( !clock ) { + if( !FD_SYSVAR_CACHE_EXISTS( sysvar_cache, clock ) ) { fd_sol_sysvar_clock_t sysvar_clock = { - .slot = 10UL, - .epoch_start_timestamp = 0L, - .epoch = 0UL, - .leader_schedule_epoch = 0UL, - .unix_timestamp = 0L - }; - fd_sysvar_clock_write( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, &sysvar_clock ); + .slot = 10UL, + .epoch_start_timestamp = 0L, + .epoch = 0UL, + .leader_schedule_epoch = 0UL, + .unix_timestamp = 0L + }; + fd_sysvar_clock_write( slot_ctx, &sysvar_clock ); } /* Epoch schedule */ // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L476-L483 - fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad ); - if( !epoch_schedule ) { + if( !FD_SYSVAR_CACHE_EXISTS( sysvar_cache, epoch_schedule ) ) { fd_epoch_schedule_t sysvar_epoch_schedule = { - .slots_per_epoch = 432000UL, - .leader_schedule_slot_offset = 432000UL, - .warmup = 1, - .first_normal_epoch = 14UL, - .first_normal_slot = 524256UL - }; + .slots_per_epoch = 432000UL, + .leader_schedule_slot_offset = 432000UL, + .warmup = 1, + .first_normal_epoch = 14UL, + .first_normal_slot = 524256UL + }; fd_sysvar_epoch_schedule_write( slot_ctx, &sysvar_epoch_schedule ); } /* Rent */ // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L487-L500 - fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad ); - if( !rent ) { + if( !FD_SYSVAR_CACHE_EXISTS( sysvar_cache, rent ) ) { fd_rent_t sysvar_rent = { - .lamports_per_uint8_year = 3480UL, - .exemption_threshold = 2.0, - .burn_percent = 50 - }; + .lamports_per_uint8_year = 3480UL, + .exemption_threshold = 2.0, + .burn_percent = 50 + }; fd_sysvar_rent_write( slot_ctx, &sysvar_rent ); } - fd_sol_sysvar_last_restart_slot_t const * last_restart_slot = fd_sysvar_last_restart_slot_read( funk, funk_txn, runner->spad ); - if( !last_restart_slot ) { - + if( !FD_SYSVAR_CACHE_EXISTS( sysvar_cache, last_restart_slot ) ) { fd_sol_sysvar_last_restart_slot_t restart = { .slot = 5000UL }; - - fd_sysvar_set( slot_ctx->bank, - slot_ctx->funk, - slot_ctx->funk_txn, - &fd_sysvar_owner_id, - &fd_sysvar_last_restart_slot_id, - &restart.slot, - sizeof(ulong), - fd_bank_slot_get( slot_ctx->bank ) ); - - } - - /* Set slot bank variables */ - clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad ); - - slot_ctx->bank->slot = clock->slot; - - /* Handle undefined behavior if sysvars are malicious (!!!) */ - - epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad ); - if( epoch_schedule ) { - fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule ); - } - - /* Override epoch bank rent setting */ - rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad ); - if( rent ) { - fd_bank_rent_set( slot_ctx->bank, *rent ); + fd_sysvar_last_restart_slot_write( slot_ctx, &restart ); } - /* Override most recent blockhash if given */ - fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad ); - fd_recent_block_hashes_t rbh[1]; - if( rbh_global ) { - rbh->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset ); + { + fd_sol_sysvar_clock_t const clock = fd_sysvar_clock_read_nofail( sysvar_cache ); + slot_ctx->bank->slot_ = clock.slot; } - if( rbh_global && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) { - fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( rbh->hashes ); - if( last ) { - block_hash_queue = (fd_block_hash_queue_global_t *)&slot_ctx->bank->block_hash_queue[0]; - fd_hash_t * last_hash = fd_block_hash_queue_last_hash_join( block_hash_queue ); - fd_memcpy( last_hash, &last->blockhash, sizeof(fd_hash_t) ); - - fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature ); - - fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature ); - } - } + /* FIXME set bank "lamports_per_signature" from blockhash queue */ /* Add accounts to bpf program cache */ fd_bpf_scan_and_create_bpf_program_cache_entry( slot_ctx, runner->spad ); diff --git a/src/flamenco/runtime/tests/harness/fd_txn_harness.c b/src/flamenco/runtime/tests/harness/fd_txn_harness.c index be6509e3db..aa745d5f37 100644 --- a/src/flamenco/runtime/tests/harness/fd_txn_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_txn_harness.c @@ -1,5 +1,6 @@ #include "fd_txn_harness.h" #include "fd_harness_common.h" +#include "../../fd_runtime_err.h" static void fd_runtime_fuzz_txn_ctx_destroy( fd_runtime_fuzz_runner_t * runner, @@ -35,8 +36,8 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, /* Set up slot context */ - slot_ctx->funk_txn = funk_txn; - slot_ctx->funk = funk; + slot_ctx->funk_txn = funk_txn; + slot_ctx->funk = funk; slot_ctx->bank = runner->bank; fd_bank_clear_bank( slot_ctx->bank ); @@ -53,7 +54,7 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, ulong slot = test_ctx->slot_ctx.slot ? test_ctx->slot_ctx.slot : 10; // Arbitrary default > 0 /* Set slot bank variables (defaults obtained from GenesisConfig::default() in Agave) */ - slot_ctx->bank->slot = slot; + slot_ctx->bank->slot_ = slot; /* Initialize builtin accounts */ fd_builtin_programs_init( slot_ctx ); @@ -85,82 +86,64 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_bank_ticks_per_slot_set( slot_ctx->bank, 64 ); - /* Set epoch bank variables if not present (defaults obtained from GenesisConfig::default() in Agave) */ - fd_epoch_schedule_t default_epoch_schedule = { - .slots_per_epoch = 432000, - .leader_schedule_slot_offset = 432000, - .warmup = 1, - .first_normal_epoch = 14, - .first_normal_slot = 524256 - }; - fd_rent_t default_rent = { - .lamports_per_uint8_year = 3480, - .exemption_threshold = 2.0, - .burn_percent = 50 - }; - fd_bank_epoch_schedule_set( slot_ctx->bank, default_epoch_schedule ); - - fd_bank_rent_set( slot_ctx->bank, default_rent ); + /* Restore sysvars from account context */ + fd_sysvar_cache_recover( slot_ctx ); + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); - fd_bank_slots_per_year_set( slot_ctx->bank, SECONDS_PER_YEAR * (1000000000.0 / (double)6250000) / (double)(fd_bank_ticks_per_slot_get( slot_ctx->bank )) ); + /* Set epoch bank variables if not present (defaults obtained from GenesisConfig::default() in Agave) */ - // Override default values if provided - fd_epoch_schedule_t * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, runner->spad ); - if( epoch_schedule ) { - fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule ); + if( !fd_sysvar_rent_is_valid( sysvar_cache ) ) { + fd_rent_t const default_rent = { + .lamports_per_uint8_year = 3480, + .exemption_threshold = 2.0, + .burn_percent = 50 + }; + fd_sysvar_rent_write( slot_ctx, &default_rent ); } - - fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad ); - if( rent ) { - fd_bank_rent_set( slot_ctx->bank, *rent ); + if( !fd_sysvar_epoch_schedule_is_valid( sysvar_cache ) ) { + fd_epoch_schedule_t const default_epoch_schedule = { + .slots_per_epoch = 432000, + .leader_schedule_slot_offset = 432000, + .warmup = 1, + .first_normal_epoch = 14, + .first_normal_slot = 524256 + }; + fd_sysvar_epoch_schedule_write( slot_ctx, &default_epoch_schedule ); } + fd_bank_slots_per_year_set( slot_ctx->bank, SECONDS_PER_YEAR * (1000000000.0 / (double)6250000) / (double)(fd_bank_ticks_per_slot_get( slot_ctx->bank )) ); + /* Provide default slot hashes of size 1 if not provided */ - fd_slot_hashes_global_t * slot_hashes = fd_sysvar_slot_hashes_read( funk, funk_txn, runner->spad ); - if( !slot_hashes ) { - FD_SPAD_FRAME_BEGIN( runner->spad ) { - /* The offseted gaddr aware types need the memory for the entire - struct to be allocated out of a contiguous memory region. */ - fd_slot_hash_t * slot_hashes = NULL; - void * mem = fd_spad_alloc( runner->spad, FD_SYSVAR_SLOT_HASHES_ALIGN, fd_sysvar_slot_hashes_footprint( 1UL ) ); - fd_slot_hashes_global_t * default_slot_hashes_global = fd_sysvar_slot_hashes_join( fd_sysvar_slot_hashes_new( mem, 1UL ), &slot_hashes ); - - fd_slot_hash_t * dummy_elem = deq_fd_slot_hash_t_push_tail_nocopy( slot_hashes ); - memset( dummy_elem, 0, sizeof(fd_slot_hash_t) ); - - fd_sysvar_slot_hashes_write( slot_ctx, default_slot_hashes_global ); - - fd_sysvar_slot_hashes_delete( fd_sysvar_slot_hashes_leave( default_slot_hashes_global, slot_hashes ) ); - } FD_SPAD_FRAME_END; + if( !fd_sysvar_slot_hashes_is_valid( sysvar_cache ) ) { + fd_sysvar_slot_hashes_init( slot_ctx ); + ulong sz_max = 0UL; + uchar * sysvar_data = fd_sysvar_cache_data_modify_prepare( + slot_ctx, &fd_sysvar_slot_hashes_id, NULL, &sz_max ); + FD_TEST( sysvar_data && sz_max>=48 ); + FD_STORE( ulong, sysvar_data, 1UL ); + fd_memset( sysvar_data+8, 0, 40 ); + fd_sysvar_cache_data_modify_commit( slot_ctx, &fd_sysvar_slot_hashes_id, 48 ); } /* Provide default stake history if not provided */ - fd_stake_history_t * stake_history = fd_sysvar_stake_history_read( funk, funk_txn, runner->spad ); - if( !stake_history ) { + if( !fd_sysvar_stake_history_is_valid( sysvar_cache ) ) { // Provide a 0-set default entry fd_epoch_stake_history_entry_pair_t entry = {0}; fd_sysvar_stake_history_init( slot_ctx ); - fd_sysvar_stake_history_update( slot_ctx, &entry, runner->spad ); + fd_sysvar_stake_history_update( slot_ctx, &entry ); } /* Provide default last restart slot sysvar if not provided */ - FD_TXN_ACCOUNT_DECL( acc ); - int err = fd_txn_account_init_from_funk_readonly( acc, &fd_sysvar_last_restart_slot_id, funk, funk_txn ); - if( err==FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) { + if( !fd_sysvar_last_restart_slot_is_valid( sysvar_cache ) ) { fd_sysvar_last_restart_slot_init( slot_ctx ); } /* Provide a default clock if not present */ - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( funk, funk_txn, runner->spad ); - if( !clock ) { - fd_sysvar_clock_init( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn ); - fd_sysvar_clock_update( slot_ctx->bank, slot_ctx->funk, slot_ctx->funk_txn, runner->spad ); + if( !fd_sysvar_clock_is_valid( sysvar_cache ) ) { + fd_sysvar_clock_init( slot_ctx ); + fd_sysvar_clock_update( slot_ctx, runner->spad ); } - /* Epoch schedule and rent get set from the epoch bank */ - fd_sysvar_epoch_schedule_init( slot_ctx ); - fd_sysvar_rent_init( slot_ctx ); - /* Set the epoch rewards sysvar if partition epoch rewards feature is enabled TODO: The init parameters are not exactly conformant with Agave's epoch rewards sysvar. We should @@ -169,21 +152,20 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, THIS MAY CHANGE IN THE FUTURE. If there are other parts of transaction execution that use the epoch rewards sysvar, we may need to update this. */ - fd_sysvar_epoch_rewards_t * epoch_rewards = fd_sysvar_epoch_rewards_read( funk, funk_txn, runner->spad ); - if( !epoch_rewards ) { + if( !fd_sysvar_epoch_rewards_is_valid( sysvar_cache ) ) { fd_point_value_t point_value = {0}; fd_hash_t const * last_hash = test_ctx->blockhash_queue_count > 0 ? (fd_hash_t const *)test_ctx->blockhash_queue[0]->bytes : (fd_hash_t const *)empty_bytes; - fd_sysvar_epoch_rewards_init( slot_ctx, 0UL, 2UL, 1UL, point_value, last_hash); + fd_sysvar_epoch_rewards_init( slot_ctx, 0UL, 2UL, 1UL, point_value, last_hash ); } /* A NaN rent exemption threshold is U.B. in Solana Labs */ - rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad ); - if( ( rent->exemption_threshold != 0.0 && - !fd_dblbits_is_normal( fd_dblbits( rent->exemption_threshold ) ) ) | - ( rent->exemption_threshold < 0.0 ) | - ( rent->exemption_threshold > 999.0 ) | - ( rent->lamports_per_uint8_year > UINT_MAX ) | - ( rent->burn_percent > 100 ) ) { + fd_rent_t const rent = fd_sysvar_rent_read_nofail( sysvar_cache ); + if( ( rent.exemption_threshold != 0.0 && + !fd_dblbits_is_normal( fd_dblbits( rent.exemption_threshold ) ) ) | + ( rent.exemption_threshold < 0.0 ) | + ( rent.exemption_threshold > 999.0 ) | + ( rent.lamports_per_uint8_year > UINT_MAX ) | + ( rent.burn_percent > 100 ) ) { return NULL; } @@ -192,32 +174,8 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, - recent_block_hashes */ ulong num_blockhashes = test_ctx->blockhash_queue_count; - /* Blockhash queue init */ - fd_block_hash_queue_global_t * block_hash_queue = fd_bank_block_hash_queue_modify( slot_ctx->bank ); - uchar * last_hash_mem = (uchar *)fd_ulong_align_up( (ulong)block_hash_queue + sizeof(fd_block_hash_queue_global_t), alignof(fd_hash_t) ); - uchar * ages_pool_mem = (uchar *)fd_ulong_align_up( (ulong)last_hash_mem + sizeof(fd_hash_t), fd_hash_hash_age_pair_t_map_align() ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( ages_pool_mem, 400 ) ); - - block_hash_queue->max_age = FD_BLOCKHASH_QUEUE_MAX_ENTRIES; - block_hash_queue->ages_root_offset = 0UL; - fd_block_hash_queue_ages_pool_update( block_hash_queue, ages_pool ); - block_hash_queue->last_hash_index = 0UL; - block_hash_queue->last_hash_offset = (ulong)last_hash_mem - (ulong)block_hash_queue; - // Save lamports per signature for most recent blockhash, if sysvar cache contains recent block hashes - fd_recent_block_hashes_global_t const * rbh_global = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad ); - fd_recent_block_hashes_t rbh[1]; - if( rbh_global ) { - rbh->hashes = deq_fd_block_block_hash_entry_t_join( (uchar*)rbh_global + rbh_global->hashes_offset ); - } - - if( rbh_global && !deq_fd_block_block_hash_entry_t_empty( rbh->hashes ) ) { - fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh->hashes ); - if( last && last->fee_calculator.lamports_per_signature!=0UL ) { - fd_bank_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature ); - fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, last->fee_calculator.lamports_per_signature ); - } - } + /* FIXME set bank "lamports_per_signature" from blockhash queue */ // Blockhash_queue[end] = last (latest) hash // Blockhash_queue[0] = genesis hash @@ -230,7 +188,7 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_block_block_hash_entry_t blockhash_entry; memcpy( &blockhash_entry.blockhash, test_ctx->blockhash_queue[i]->bytes, sizeof(fd_hash_t) ); fd_bank_poh_set( slot_ctx->bank, blockhash_entry.blockhash ); - fd_sysvar_recent_hashes_update( slot_ctx, runner->spad ); + fd_sysvar_recent_hashes_update( slot_ctx ); } } else { // Add a default empty blockhash and use it as genesis @@ -240,7 +198,7 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_block_block_hash_entry_t blockhash_entry; memcpy( &blockhash_entry.blockhash, empty_bytes, sizeof(fd_hash_t) ); fd_bank_poh_set( slot_ctx->bank, blockhash_entry.blockhash ); - fd_sysvar_recent_hashes_update( slot_ctx, runner->spad ); + fd_sysvar_recent_hashes_update( slot_ctx ); } /* Add accounts to bpf program cache */ diff --git a/src/flamenco/snapshot/fd_snapshot.c b/src/flamenco/snapshot/fd_snapshot.c index b41b74e32a..0ee8baa361 100644 --- a/src/flamenco/snapshot/fd_snapshot.c +++ b/src/flamenco/snapshot/fd_snapshot.c @@ -230,7 +230,7 @@ fd_snapshot_load_fini( fd_snapshot_load_ctx_t * ctx ) { // In order to calculate the snapshot hash, we need to know what features are active... fd_features_restore( ctx->slot_ctx, ctx->runtime_spad ); - fd_calculate_epoch_accounts_hash_values( ctx->slot_ctx ); + fd_calculate_epoch_accounts_hash_values( ctx->slot_ctx->bank ); int snapshots_lt_hash = FD_FEATURE_ACTIVE_BANK( ctx->slot_ctx->bank, snapshots_lt_hash ); int accounts_lt_hash = FD_FEATURE_ACTIVE_BANK( ctx->slot_ctx->bank, accounts_lt_hash ); diff --git a/src/flamenco/snapshot/test_snapshot_restore.c b/src/flamenco/snapshot/test_snapshot_restore.c index 456ed935fe..690c7d49dd 100644 --- a/src/flamenco/snapshot/test_snapshot_restore.c +++ b/src/flamenco/snapshot/test_snapshot_restore.c @@ -1,6 +1,7 @@ #include "fd_snapshot_restore.h" #include "fd_snapshot_restore_private.h" #include "../runtime/fd_acc_mgr.h" +#include "../../funk/fd_funk.h" #include static void diff --git a/src/flamenco/stakes/fd_stakes.c b/src/flamenco/stakes/fd_stakes.c index d213b8f915..fededeed4d 100644 --- a/src/flamenco/stakes/fd_stakes.c +++ b/src/flamenco/stakes/fd_stakes.c @@ -3,6 +3,7 @@ #include "../runtime/context/fd_exec_slot_ctx.h" #include "../runtime/program/fd_stake_program.h" #include "../runtime/sysvar/fd_sysvar_stake_history.h" +#include "../runtime/fd_acc_mgr.h" /* fd_stakes_accum_by_node converts Stakes (unordered list of (vote acc, active stake) tuples) to StakedNodes (rbtree mapping (node identity) @@ -152,18 +153,22 @@ fd_stake_weights_by_node( fd_vote_accounts_global_t const * accs, /* Create rb tree */ - void * pool_mem = fd_spad_alloc( runtime_spad, rb_align, rb_footprint ); - pool_mem = fd_stake_weight_t_map_new( pool_mem, vote_acc_cnt ); - fd_stake_weight_t_mapnode_t * pool = fd_stake_weight_t_map_join( pool_mem ); - if( FD_UNLIKELY( !pool_mem ) ) FD_LOG_CRIT(( "fd_stake_weights_new() failed" )); + ulong weights_cnt = 0UL; + FD_SPAD_FRAME_BEGIN( runtime_spad ) { + void * pool_mem = fd_spad_alloc_check( runtime_spad, rb_align, rb_footprint ); + pool_mem = fd_stake_weight_t_map_new( pool_mem, vote_acc_cnt ); + fd_stake_weight_t_mapnode_t * pool = fd_stake_weight_t_map_join( pool_mem ); + if( FD_UNLIKELY( !pool_mem ) ) FD_LOG_CRIT(( "fd_stake_weights_new() failed" )); - /* Accumulate stakes to rb tree */ + /* Accumulate stakes to rb tree */ - fd_stake_weight_t_mapnode_t const * root = fd_stakes_accum_by_node( accs, pool, runtime_spad ); + fd_stake_weight_t_mapnode_t const * root = fd_stakes_accum_by_node( accs, pool, runtime_spad ); - /* Export to sorted list */ + /* Export to sorted list */ - ulong weights_cnt = fd_stakes_export( pool, root, weights ); + weights_cnt = fd_stakes_export( pool, root, weights ); + } + FD_SPAD_FRAME_END; fd_stake_weight_sort( weights, weights_cnt ); return weights_cnt; @@ -814,7 +819,8 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, /* Add a new entry to the Stake History sysvar for the previous epoch https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/runtime/src/stakes.rs#L181-L192 */ - fd_stake_history_t const * history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad ); + fd_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( slot_ctx->bank ); + fd_stake_history_t const * history = fd_sysvar_stake_history_join_const( sysvar_cache ); if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "StakeHistory sysvar is missing from sysvar cache" )); ulong stake_delegations_size = fd_delegation_pair_t_map_size( @@ -846,6 +852,8 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, exec_spad_cnt, runtime_spad ); + fd_sysvar_stake_history_leave_const( sysvar_cache, history ); + /* https://github.com/anza-xyz/agave/blob/v2.1.6/runtime/src/stakes.rs#L359 */ fd_epoch_stake_history_entry_pair_t new_elem = { .epoch = stakes->epoch, @@ -856,7 +864,7 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, } }; - fd_sysvar_stake_history_update( slot_ctx, &new_elem, runtime_spad ); + fd_sysvar_stake_history_update( slot_ctx, &new_elem ); fd_bank_stakes_end_locking_query( slot_ctx->bank ); diff --git a/src/flamenco/types/fd_fuzz_types.h b/src/flamenco/types/fd_fuzz_types.h index 2e87cd2c75..e85ca95d7e 100644 --- a/src/flamenco/types/fd_fuzz_types.h +++ b/src/flamenco/types/fd_fuzz_types.h @@ -127,35 +127,6 @@ void *fd_block_hash_vec_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) return mem; } -void *fd_block_hash_queue_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) { - fd_block_hash_queue_t *self = (fd_block_hash_queue_t *) mem; - *alloc_mem = (uchar *) *alloc_mem + sizeof(fd_block_hash_queue_t); - fd_block_hash_queue_new(mem); - self->last_hash_index = fd_rng_ulong( rng ); - { - uchar is_null = fd_rng_uchar( rng ) % 2; - if( !is_null ) { - self->last_hash = (fd_hash_t *) *alloc_mem; - *alloc_mem = (uchar *) *alloc_mem + sizeof(fd_hash_t); - fd_hash_new( self->last_hash ); - fd_hash_generate( self->last_hash, alloc_mem, rng ); - } - else { - self->last_hash = NULL; - } - } - ulong ages_len = fd_rng_ulong( rng ) % 8; - self->ages_pool = fd_hash_hash_age_pair_t_map_join_new( alloc_mem, fd_ulong_max( ages_len, 400 ) ); - self->ages_root = NULL; - for( ulong i=0; i < ages_len; i++ ) { - fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( self->ages_pool ); - fd_hash_hash_age_pair_generate( &node->elem, alloc_mem, rng ); - fd_hash_hash_age_pair_t_map_insert( self->ages_pool, &self->ages_root, node ); - } - self->max_age = fd_rng_ulong( rng ); - return mem; -} - void *fd_fee_rate_governor_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) { fd_fee_rate_governor_t *self = (fd_fee_rate_governor_t *) mem; *alloc_mem = (uchar *) *alloc_mem + sizeof(fd_fee_rate_governor_t); diff --git a/src/flamenco/types/fd_types.c b/src/flamenco/types/fd_types.c index 07fa594b51..ab42d2a303 100644 --- a/src/flamenco/types/fd_types.c +++ b/src/flamenco/types/fd_types.c @@ -524,250 +524,6 @@ ulong fd_block_hash_vec_size_global( fd_block_hash_vec_global_t const * self ) { return size; } -int fd_block_hash_queue_encode( fd_block_hash_queue_t const * self, fd_bincode_encode_ctx_t * ctx ) { - int err; - err = fd_bincode_uint64_encode( self->last_hash_index, ctx ); - if( FD_UNLIKELY( err ) ) return err; - if( self->last_hash != NULL ) { - err = fd_bincode_bool_encode( 1, ctx ); - if( FD_UNLIKELY( err ) ) return err; - err = fd_hash_encode( self->last_hash, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } else { - err = fd_bincode_bool_encode( 0, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - if( self->ages_root ) { - ulong ages_len = fd_hash_hash_age_pair_t_map_size( self->ages_pool, self->ages_root ); - err = fd_bincode_uint64_encode( ages_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( self->ages_pool, self->ages_root ); n; n = fd_hash_hash_age_pair_t_map_successor( self->ages_pool, n ) ) { - err = fd_hash_hash_age_pair_encode( &n->elem, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - } else { - ulong ages_len = 0; - err = fd_bincode_uint64_encode( ages_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - err = fd_bincode_uint64_encode( self->max_age, ctx ); - if( FD_UNLIKELY( err ) ) return err; - return FD_BINCODE_SUCCESS; -} -int fd_block_hash_queue_encode_global( fd_block_hash_queue_global_t const * self, fd_bincode_encode_ctx_t * ctx ) { - int err; - err = fd_bincode_uint64_encode( self->last_hash_index, ctx ); - if( FD_UNLIKELY( err ) ) return err; - if( self->last_hash_offset ) { - err = fd_bincode_bool_encode( 1, ctx ); - if( FD_UNLIKELY( err ) ) return err; - fd_hash_t * last_hash = (void *)((uchar*)self + self->last_hash_offset); - err = fd_hash_encode( last_hash, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } else { - err = fd_bincode_bool_encode( 0, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - fd_hash_hash_age_pair_t_mapnode_t * ages_root = fd_hash_hash_age_pair_t_map_join( (uchar *)self + self->ages_root_offset ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join( (uchar *)self + self->ages_pool_offset ); - if( ages_root ) { - ulong ages_len = fd_hash_hash_age_pair_t_map_size( ages_pool, ages_root ); - err = fd_bincode_uint64_encode( ages_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( ages_pool, ages_root ); n; n = fd_hash_hash_age_pair_t_map_successor( ages_pool, n ) ) { - err = fd_hash_hash_age_pair_encode( &n->elem, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - } else { - ulong ages_len = 0; - err = fd_bincode_uint64_encode( ages_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - err = fd_bincode_uint64_encode( self->max_age, ctx ); - if( FD_UNLIKELY( err ) ) return err; - return FD_BINCODE_SUCCESS; -} -static int fd_block_hash_queue_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { - if( ctx->data>=ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; - int err = 0; - err = fd_bincode_uint64_decode_footprint( ctx ); - if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; - { - uchar o; - err = fd_bincode_bool_decode( &o, ctx ); - if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; - if( o ) { - *total_sz += FD_HASH_ALIGN + sizeof(fd_hash_t); - err = fd_hash_decode_footprint_inner( ctx, total_sz ); - if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; - } - } - ulong ages_len = 0UL; - err = fd_bincode_uint64_decode( &ages_len, ctx ); - ulong ages_cnt = fd_ulong_max( ages_len, 400 ); - *total_sz += fd_hash_hash_age_pair_t_map_align() + fd_hash_hash_age_pair_t_map_footprint( ages_cnt ); - if( FD_UNLIKELY( err ) ) return err; - for( ulong i=0; i < ages_len; i++ ) { - err = fd_hash_hash_age_pair_decode_footprint_inner( ctx, total_sz ); - if( FD_UNLIKELY( err ) ) return err; - } - err = fd_bincode_uint64_decode_footprint( ctx ); - if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; - return 0; -} -int fd_block_hash_queue_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { - *total_sz += sizeof(fd_block_hash_queue_t); - void const * start_data = ctx->data; - int err = fd_block_hash_queue_decode_footprint_inner( ctx, total_sz ); - if( ctx->data>ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; - ctx->data = start_data; - return err; -} -static void fd_block_hash_queue_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { - fd_block_hash_queue_t * self = (fd_block_hash_queue_t *)struct_mem; - fd_bincode_uint64_decode_unsafe( &self->last_hash_index, ctx ); - { - uchar o; - fd_bincode_bool_decode_unsafe( &o, ctx ); - if( o ) { - *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, FD_HASH_ALIGN ); - self->last_hash = *alloc_mem; - *alloc_mem = (uchar *)*alloc_mem + sizeof(fd_hash_t); - fd_hash_new( self->last_hash ); - fd_hash_decode_inner( self->last_hash, alloc_mem, ctx ); - } else { - self->last_hash = NULL; - } - } - ulong ages_len; - fd_bincode_uint64_decode_unsafe( &ages_len, ctx ); - self->ages_pool = fd_hash_hash_age_pair_t_map_join_new( alloc_mem, fd_ulong_max( ages_len, 400 ) ); - self->ages_root = NULL; - for( ulong i=0; i < ages_len; i++ ) { - fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( self->ages_pool ); - fd_hash_hash_age_pair_new( &node->elem ); - fd_hash_hash_age_pair_decode_inner( &node->elem, alloc_mem, ctx ); - fd_hash_hash_age_pair_t_mapnode_t * out = NULL;; - fd_hash_hash_age_pair_t_map_insert_or_replace( self->ages_pool, &self->ages_root, node, &out ); - if( out != NULL ) { - // Unclear how to release the memory... - fd_hash_hash_age_pair_t_map_release( self->ages_pool, out ); - } - } - fd_bincode_uint64_decode_unsafe( &self->max_age, ctx ); -} -void * fd_block_hash_queue_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) { - fd_block_hash_queue_t * self = (fd_block_hash_queue_t *)mem; - fd_block_hash_queue_new( self ); - void * alloc_region = (uchar *)mem + sizeof(fd_block_hash_queue_t); - void * * alloc_mem = &alloc_region; - fd_block_hash_queue_decode_inner( mem, alloc_mem, ctx ); - return self; -} -static void fd_block_hash_queue_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { - fd_block_hash_queue_global_t * self = (fd_block_hash_queue_global_t *)struct_mem; - fd_bincode_uint64_decode_unsafe( &self->last_hash_index, ctx ); - { - uchar o; - fd_bincode_bool_decode_unsafe( &o, ctx ); - if( o ) { - *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, FD_HASH_ALIGN ); - self->last_hash_offset = (ulong)*alloc_mem - (ulong)struct_mem; - fd_hash_new( *alloc_mem ); - *alloc_mem = (uchar *)*alloc_mem + sizeof(fd_hash_t); - fd_hash_decode_inner( (uchar*)self + self->last_hash_offset, alloc_mem, ctx ); - } else { - self->last_hash_offset = 0UL; - } - } - ulong ages_len; - fd_bincode_uint64_decode_unsafe( &ages_len, ctx ); - *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, fd_hash_hash_age_pair_t_map_align() ); - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = fd_hash_hash_age_pair_t_map_join_new( alloc_mem, fd_ulong_max( ages_len, 400 ) ); - fd_hash_hash_age_pair_t_mapnode_t * ages_root = NULL; - for( ulong i=0; i < ages_len; i++ ) { - fd_hash_hash_age_pair_t_mapnode_t * node = fd_hash_hash_age_pair_t_map_acquire( ages_pool ); - fd_hash_hash_age_pair_new( (fd_hash_hash_age_pair_t *)fd_type_pun(&node->elem) ); - fd_hash_hash_age_pair_decode_inner( &node->elem, alloc_mem, ctx ); - fd_hash_hash_age_pair_t_map_insert( ages_pool, &ages_root, node ); - } - self->ages_pool_offset = (ulong)fd_hash_hash_age_pair_t_map_leave( ages_pool ) - (ulong)struct_mem; - self->ages_root_offset = (ulong)ages_root - (ulong)struct_mem; - fd_bincode_uint64_decode_unsafe( &self->max_age, ctx ); -} -void * fd_block_hash_queue_decode_global( void * mem, fd_bincode_decode_ctx_t * ctx ) { - fd_block_hash_queue_global_t * self = (fd_block_hash_queue_global_t *)mem; - fd_block_hash_queue_new( (fd_block_hash_queue_t *)self ); - void * alloc_region = (uchar *)mem + sizeof(fd_block_hash_queue_global_t); - void * * alloc_mem = &alloc_region; - fd_block_hash_queue_decode_inner_global( mem, alloc_mem, ctx ); - return self; -} -void fd_block_hash_queue_new(fd_block_hash_queue_t * self) { - fd_memset( self, 0, sizeof(fd_block_hash_queue_t) ); -} -void fd_block_hash_queue_walk( void * w, fd_block_hash_queue_t const * self, fd_types_walk_fn_t fun, const char *name, uint level, uint varint ) { - (void) varint; - fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_block_hash_queue", level++, 0 ); - fun( w, &self->last_hash_index, "last_hash_index", FD_FLAMENCO_TYPE_ULONG, "ulong", level, 0 ); - if( !self->last_hash ) { - fun( w, NULL, "last_hash", FD_FLAMENCO_TYPE_NULL, "hash", level, 0 ); - } else { - fd_hash_walk( w, self->last_hash, fun, "last_hash", level, 0 ); - } - if( self->ages_root ) { - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum(self->ages_pool, self->ages_root ); n; n = fd_hash_hash_age_pair_t_map_successor( self->ages_pool, n ) ) { - fd_hash_hash_age_pair_walk(w, &n->elem, fun, "ages", level, 0 ); - } - } - fun( w, &self->max_age, "max_age", FD_FLAMENCO_TYPE_ULONG, "ulong", level, 0 ); - fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_block_hash_queue", level--, 0 ); -} -ulong fd_block_hash_queue_size( fd_block_hash_queue_t const * self ) { - ulong size = 0; - size += sizeof(ulong); - size += sizeof(char); - if( NULL != self->last_hash ) { - size += fd_hash_size( self->last_hash ); - } - if( self->ages_root ) { - size += sizeof(ulong); - ulong max = fd_hash_hash_age_pair_t_map_max( self->ages_pool ); - size += fd_hash_hash_age_pair_t_map_footprint( max ); - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( self->ages_pool, self->ages_root ); n; n = fd_hash_hash_age_pair_t_map_successor( self->ages_pool, n ) ) { - size += fd_hash_hash_age_pair_size( &n->elem ) - sizeof(fd_hash_hash_age_pair_t); - } - } else { - size += sizeof(ulong); - } - size += sizeof(ulong); - return size; -} - -ulong fd_block_hash_queue_size_global( fd_block_hash_queue_global_t const * self ) { - ulong size = 0; - size += sizeof(ulong); - size += sizeof(char); - fd_hash_t * last_hash = (fd_hash_t *)fd_type_pun( (uchar *)self + self->last_hash_offset ); - if( NULL != last_hash ) { - size += fd_hash_size( last_hash ); - } - fd_hash_hash_age_pair_t_mapnode_t * ages_pool = !!self->ages_pool_offset ? (fd_hash_hash_age_pair_t_mapnode_t *)fd_hash_hash_age_pair_t_map_join( fd_type_pun( (uchar *)self + self->ages_pool_offset ) ) : NULL; // bruuu - fd_hash_hash_age_pair_t_mapnode_t * ages_root = !!self->ages_root_offset ? (fd_hash_hash_age_pair_t_mapnode_t *)fd_type_pun( (uchar *)self + self->ages_root_offset ) : NULL; - if( ages_root ) { - size += sizeof(ulong); - ulong max = fd_hash_hash_age_pair_t_map_max( ages_pool ); - size += fd_hash_hash_age_pair_t_map_footprint( max ); - for( fd_hash_hash_age_pair_t_mapnode_t * n = fd_hash_hash_age_pair_t_map_minimum( ages_pool, ages_root ); n; n = fd_hash_hash_age_pair_t_map_successor( ages_pool, n ) ) { - size += fd_hash_hash_age_pair_size( &n->elem ) - sizeof(fd_hash_hash_age_pair_t); - } - } else { - size += sizeof(ulong); - } - size += sizeof(ulong); - return size; -} - int fd_fee_rate_governor_encode( fd_fee_rate_governor_t const * self, fd_bincode_encode_ctx_t * ctx ) { int err; err = fd_bincode_uint64_encode( self->target_lamports_per_signature, ctx ); @@ -26913,13 +26669,6 @@ int fd_rent_state_encode( fd_rent_state_t const * self, fd_bincode_encode_ctx_t return fd_rent_state_inner_encode( &self->inner, self->discriminant, ctx ); } -#define REDBLK_T fd_hash_hash_age_pair_t_mapnode_t -#define REDBLK_NAME fd_hash_hash_age_pair_t_map -#define REDBLK_IMPL_STYLE 2 -#include "../../util/tmpl/fd_redblack.c" -long fd_hash_hash_age_pair_t_map_compare( fd_hash_hash_age_pair_t_mapnode_t * left, fd_hash_hash_age_pair_t_mapnode_t * right ) { - return memcmp( left->elem.key.uc, right->elem.key.uc, sizeof(right->elem.key) ); -} #define REDBLK_T fd_vote_accounts_pair_t_mapnode_t #define REDBLK_NAME fd_vote_accounts_pair_t_map #define REDBLK_IMPL_STYLE 2 diff --git a/src/flamenco/types/fd_types.h b/src/flamenco/types/fd_types.h index 2630aea84f..aaa610a640 100644 --- a/src/flamenco/types/fd_types.h +++ b/src/flamenco/types/fd_types.h @@ -71,64 +71,6 @@ FD_FN_UNUSED static fd_hash_hash_age_pair_t * fd_block_hash_vec_ages_join( fd_bl FD_FN_UNUSED static void fd_block_hash_vec_ages_update( fd_block_hash_vec_global_t * struct_mem, fd_hash_hash_age_pair_t * vec ) { struct_mem->ages_offset = !!vec ? (ulong)vec - (ulong)struct_mem : 0UL; } -typedef struct fd_hash_hash_age_pair_t_mapnode fd_hash_hash_age_pair_t_mapnode_t; -#define REDBLK_T fd_hash_hash_age_pair_t_mapnode_t -#define REDBLK_NAME fd_hash_hash_age_pair_t_map -#define REDBLK_IMPL_STYLE 1 -#include "../../util/tmpl/fd_redblack.c" -struct fd_hash_hash_age_pair_t_mapnode { - fd_hash_hash_age_pair_t elem; - ulong redblack_parent; - ulong redblack_left; - ulong redblack_right; - int redblack_color; -}; -static inline fd_hash_hash_age_pair_t_mapnode_t * -fd_hash_hash_age_pair_t_map_join_new( void * * alloc_mem, ulong len ) { - if( FD_UNLIKELY( 0 == len ) ) len = 1; // prevent underflow - *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, fd_hash_hash_age_pair_t_map_align() ); - void * map_mem = *alloc_mem; - *alloc_mem = (uchar *)*alloc_mem + fd_hash_hash_age_pair_t_map_footprint( len ); - return fd_hash_hash_age_pair_t_map_join( fd_hash_hash_age_pair_t_map_new( map_mem, len ) ); -} -/* Encoded Size: Dynamic */ -struct __attribute__((aligned(128UL))) fd_block_hash_queue { - ulong last_hash_index; - fd_hash_t * last_hash; - fd_hash_hash_age_pair_t_mapnode_t * ages_pool; - fd_hash_hash_age_pair_t_mapnode_t * ages_root; - ulong max_age; -}; -typedef struct fd_block_hash_queue fd_block_hash_queue_t; -#define FD_BLOCK_HASH_QUEUE_ALIGN (128UL) - -struct __attribute__((aligned(128UL))) fd_block_hash_queue_global { - ulong last_hash_index; - ulong last_hash_offset; - ulong ages_pool_offset; - ulong ages_root_offset; - ulong max_age; -}; -typedef struct fd_block_hash_queue_global fd_block_hash_queue_global_t; -#define FD_BLOCK_HASH_QUEUE_GLOBAL_ALIGN (128UL) - -FD_FN_UNUSED static fd_hash_t * fd_block_hash_queue_last_hash_join( fd_block_hash_queue_global_t const * struct_mem ) { - return struct_mem->last_hash_offset ? (fd_hash_t *)fd_type_pun( (uchar *)struct_mem + struct_mem->last_hash_offset ) : NULL; -} -static FD_FN_UNUSED fd_hash_hash_age_pair_t_mapnode_t * fd_block_hash_queue_ages_pool_join( fd_block_hash_queue_global_t const * type ) { - if( FD_UNLIKELY( !type ) ) return NULL; - return !!type->ages_pool_offset ? (fd_hash_hash_age_pair_t_mapnode_t *)fd_hash_hash_age_pair_t_map_join( fd_type_pun( (uchar *)type + type->ages_pool_offset ) ) : NULL; -} -static FD_FN_UNUSED fd_hash_hash_age_pair_t_mapnode_t * fd_block_hash_queue_ages_root_join( fd_block_hash_queue_global_t const * type ) { - if( FD_UNLIKELY( !type ) ) return NULL; - return !!type->ages_root_offset ? (fd_hash_hash_age_pair_t_mapnode_t *)fd_type_pun( (uchar *)type + type->ages_root_offset ) : NULL; -} -static FD_FN_UNUSED void fd_block_hash_queue_ages_pool_update( fd_block_hash_queue_global_t * type, fd_hash_hash_age_pair_t_mapnode_t * pool ) { - type->ages_pool_offset = !!pool ? (ulong)fd_hash_hash_age_pair_t_map_leave( pool ) - (ulong)type : 0UL; -} -static FD_FN_UNUSED void fd_block_hash_queue_ages_root_update( fd_block_hash_queue_global_t * type, fd_hash_hash_age_pair_t_mapnode_t * root ) { - type->ages_root_offset = !!root ? (ulong)root - (ulong)type : 0UL; -} /* Encoded Size: Fixed (33 bytes) */ struct fd_fee_rate_governor { ulong target_lamports_per_signature; @@ -231,7 +173,7 @@ typedef struct fd_epoch_stake_history_entry_pair fd_epoch_stake_history_entry_pa #define FD_EPOCH_STAKE_HISTORY_ENTRY_PAIR_ALIGN alignof(fd_epoch_stake_history_entry_pair_t) /* https://github.com/firedancer-io/solana/blob/v1.17/sdk/program/src/stake_history.rs#L12-L75 */ -/* Encoded Size: Dynamic */ +/* Encoded Size: Fixed (16392 bytes) */ struct fd_stake_history { ulong fd_stake_history_len; ulong fd_stake_history_size; @@ -3709,17 +3651,6 @@ void * fd_block_hash_vec_decode_global( void * mem, fd_bincode_decode_ctx_t * ct int fd_block_hash_vec_encode_global( fd_block_hash_vec_global_t const * self, fd_bincode_encode_ctx_t * ctx ); ulong fd_block_hash_vec_size_global( fd_block_hash_vec_global_t const * self ); -void fd_block_hash_queue_new( fd_block_hash_queue_t * self ); -int fd_block_hash_queue_encode( fd_block_hash_queue_t const * self, fd_bincode_encode_ctx_t * ctx ); -void fd_block_hash_queue_walk( void * w, fd_block_hash_queue_t const * self, fd_types_walk_fn_t fun, const char *name, uint level, uint varint ); -ulong fd_block_hash_queue_size( fd_block_hash_queue_t const * self ); -static inline ulong fd_block_hash_queue_align( void ) { return FD_BLOCK_HASH_QUEUE_ALIGN; } -int fd_block_hash_queue_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); -void * fd_block_hash_queue_decode( void * mem, fd_bincode_decode_ctx_t * ctx ); -void * fd_block_hash_queue_decode_global( void * mem, fd_bincode_decode_ctx_t * ctx ); -int fd_block_hash_queue_encode_global( fd_block_hash_queue_global_t const * self, fd_bincode_encode_ctx_t * ctx ); -ulong fd_block_hash_queue_size_global( fd_block_hash_queue_global_t const * self ); - static inline void fd_fee_rate_governor_new( fd_fee_rate_governor_t * self ) { fd_memset( self, 0, sizeof(fd_fee_rate_governor_t) ); } int fd_fee_rate_governor_encode( fd_fee_rate_governor_t const * self, fd_bincode_encode_ctx_t * ctx ); void fd_fee_rate_governor_walk( void * w, fd_fee_rate_governor_t const * self, fd_types_walk_fn_t fun, const char *name, uint level, uint varint ); diff --git a/src/flamenco/types/fd_types.json b/src/flamenco/types/fd_types.json index da32c8b2e5..1b479d9b23 100644 --- a/src/flamenco/types/fd_types.json +++ b/src/flamenco/types/fd_types.json @@ -84,18 +84,6 @@ { "name": "max_age", "type": "ulong" } ] }, - { - "name": "block_hash_queue", - "type": "struct", - "global": true, - "alignment": "128", - "fields": [ - { "name": "last_hash_index", "type": "ulong" }, - { "name": "last_hash", "type": "option", "element": "hash" }, - { "name": "ages", "type": "map", "element": "hash_hash_age_pair", "key": "key", "minalloc": 400 }, - { "name": "max_age", "type": "ulong" } - ] - }, { "name": "fee_rate_governor", "type": "struct", diff --git a/src/flamenco/types/fd_types_reflect_generated.c b/src/flamenco/types/fd_types_reflect_generated.c index 89e2b75cc2..f472615152 100644 --- a/src/flamenco/types/fd_types_reflect_generated.c +++ b/src/flamenco/types/fd_types_reflect_generated.c @@ -3,7 +3,7 @@ #include "fd_types_custom.h" #include "fd_types_reflect_private.h" #pragma GCC diagnostic ignored "-Wpedantic" -ulong fd_types_vt_list_cnt = 249; +ulong fd_types_vt_list_cnt = 248; fd_types_vt_t const fd_types_vt_list[] = { { .name="fd_hash", .name_len=7, .align=FD_HASH_ALIGN, .new_=(void *)fd_hash_new, .decode=(void *)fd_hash_decode, .size=(void *)fd_hash_size, .walk=(void *)fd_hash_walk, .decode_footprint=(void *)fd_hash_decode_footprint, .encode=(void *)fd_hash_encode }, { .name="fd_pubkey", .name_len=9, .align=FD_PUBKEY_ALIGN, .new_=(void *)fd_pubkey_new, .decode=(void *)fd_pubkey_decode, .size=(void *)fd_pubkey_size, .walk=(void *)fd_pubkey_walk, .decode_footprint=(void *)fd_pubkey_decode_footprint, .encode=(void *)fd_pubkey_encode }, @@ -15,7 +15,6 @@ fd_types_vt_t const fd_types_vt_list[] = { { .name="fd_hash_age", .name_len=11, .align=FD_HASH_AGE_ALIGN, .new_=(void *)fd_hash_age_new, .decode=(void *)fd_hash_age_decode, .size=(void *)fd_hash_age_size, .walk=(void *)fd_hash_age_walk, .decode_footprint=(void *)fd_hash_age_decode_footprint, .encode=(void *)fd_hash_age_encode }, { .name="fd_hash_hash_age_pair", .name_len=21, .align=FD_HASH_HASH_AGE_PAIR_ALIGN, .new_=(void *)fd_hash_hash_age_pair_new, .decode=(void *)fd_hash_hash_age_pair_decode, .size=(void *)fd_hash_hash_age_pair_size, .walk=(void *)fd_hash_hash_age_pair_walk, .decode_footprint=(void *)fd_hash_hash_age_pair_decode_footprint, .encode=(void *)fd_hash_hash_age_pair_encode }, { .name="fd_block_hash_vec", .name_len=17, .align=FD_BLOCK_HASH_VEC_ALIGN, .new_=(void *)fd_block_hash_vec_new, .decode=(void *)fd_block_hash_vec_decode, .size=(void *)fd_block_hash_vec_size, .walk=(void *)fd_block_hash_vec_walk, .decode_footprint=(void *)fd_block_hash_vec_decode_footprint, .encode=(void *)fd_block_hash_vec_encode }, - { .name="fd_block_hash_queue", .name_len=19, .align=FD_BLOCK_HASH_QUEUE_ALIGN, .new_=(void *)fd_block_hash_queue_new, .decode=(void *)fd_block_hash_queue_decode, .size=(void *)fd_block_hash_queue_size, .walk=(void *)fd_block_hash_queue_walk, .decode_footprint=(void *)fd_block_hash_queue_decode_footprint, .encode=(void *)fd_block_hash_queue_encode }, { .name="fd_fee_rate_governor", .name_len=20, .align=FD_FEE_RATE_GOVERNOR_ALIGN, .new_=(void *)fd_fee_rate_governor_new, .decode=(void *)fd_fee_rate_governor_decode, .size=(void *)fd_fee_rate_governor_size, .walk=(void *)fd_fee_rate_governor_walk, .decode_footprint=(void *)fd_fee_rate_governor_decode_footprint, .encode=(void *)fd_fee_rate_governor_encode }, { .name="fd_slot_pair", .name_len=12, .align=FD_SLOT_PAIR_ALIGN, .new_=(void *)fd_slot_pair_new, .decode=(void *)fd_slot_pair_decode, .size=(void *)fd_slot_pair_size, .walk=(void *)fd_slot_pair_walk, .decode_footprint=(void *)fd_slot_pair_decode_footprint, .encode=(void *)fd_slot_pair_encode }, { .name="fd_hard_forks", .name_len=13, .align=FD_HARD_FORKS_ALIGN, .new_=(void *)fd_hard_forks_new, .decode=(void *)fd_hard_forks_decode, .size=(void *)fd_hard_forks_size, .walk=(void *)fd_hard_forks_walk, .decode_footprint=(void *)fd_hard_forks_decode_footprint, .encode=(void *)fd_hard_forks_encode }, diff --git a/src/flamenco/types/gen_stubs.py b/src/flamenco/types/gen_stubs.py index 57643fd54f..aa87129737 100644 --- a/src/flamenco/types/gen_stubs.py +++ b/src/flamenco/types/gen_stubs.py @@ -1022,7 +1022,10 @@ def __init__(self, container, json): self.ignore_underflow = (bool(json["ignore_underflow"]) if "ignore_underflow" in json else False) def isFixedSize(self): - return False + return self.element in fixedsizetypes + + def fixedSize(self): + return 8 + self.size * fixedsizetypes[self.element] def isFlat(self): return self.element in flattypes @@ -1833,7 +1836,6 @@ def emitDecodeInner(self): print(f' {nodename} * out = NULL;;', file=body) print(f' {mapname}_insert_or_replace( self->{self.name}_pool, &self->{self.name}_root, node, &out );', file=body) print(f' if( out != NULL ) {{', file=body) - print(f' // Unclear how to release the memory...', file=body) print(f' {mapname}_release( self->{self.name}_pool, out );', file=body) print(f' }}', file=body) print(' }', file=body) @@ -1959,7 +1961,7 @@ def emitSizeGlobal(self, inner, indent=''): mapname = element_type + "_map" nodename = element_type + "_mapnode_t" - print(f' {nodename} * {self.name}_pool = !!self->{self.name}_pool_offset ? ({nodename} *){mapname}_join( fd_type_pun( (uchar *)self + self->{self.name}_pool_offset ) ) : NULL; // bruuu', file=body) + print(f' {nodename} * {self.name}_pool = !!self->{self.name}_pool_offset ? ({nodename} *){mapname}_join( fd_type_pun( (uchar *)self + self->{self.name}_pool_offset ) ) : NULL;', file=body) print(f' {nodename} * {self.name}_root = !!self->{self.name}_root_offset ? ({nodename} *)fd_type_pun( (uchar *)self + self->{self.name}_root_offset ) : NULL;', file=body) print(f' if( {self.name}_root ) {{', file=body) if self.compact: diff --git a/src/flamenco/vm/fd_vm.c b/src/flamenco/vm/fd_vm.c index 47ce173fd9..3953648108 100644 --- a/src/flamenco/vm/fd_vm.c +++ b/src/flamenco/vm/fd_vm.c @@ -34,7 +34,6 @@ fd_vm_syscall_strerror( int err ) { case FD_VM_SYSCALL_ERR_INVALID_POINTER: return "Invalid pointer"; case FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW: return "Arithmetic overflow"; - case FD_VM_SYSCALL_ERR_INSTR_ERR: return "Instruction error"; case FD_VM_SYSCALL_ERR_INVALID_PDA: return "Invalid PDA"; case FD_VM_SYSCALL_ERR_COMPUTE_BUDGET_EXCEEDED: return "Compute budget exceeded"; case FD_VM_SYSCALL_ERR_SEGFAULT: return "Segmentation fault"; @@ -102,7 +101,6 @@ fd_vm_strerror( int err ) { case FD_VM_ERR_FULL: return "FULL storage full"; case FD_VM_ERR_EMPTY: return "EMPTY nothing to do"; case FD_VM_ERR_IO: return "IO input-output error"; - case FD_VM_ERR_AGAIN: return "AGAIN try again later"; /* VM exec error codes */ diff --git a/src/flamenco/vm/fd_vm_base.h b/src/flamenco/vm/fd_vm_base.h index 33c14fab2b..f0604da3e5 100644 --- a/src/flamenco/vm/fd_vm_base.h +++ b/src/flamenco/vm/fd_vm_base.h @@ -22,7 +22,6 @@ #define FD_VM_SUCCESS ( 0) /* success */ #define FD_VM_ERR_INVAL (-1) /* invalid request */ -#define FD_VM_ERR_AGAIN (-2) /* try again later */ #define FD_VM_ERR_UNSUP (-3) /* unsupported request */ #define FD_VM_ERR_PERM (-4) /* unauthorized request */ #define FD_VM_ERR_FULL (-5) /* storage full */ @@ -105,7 +104,6 @@ #define FD_VM_SYSCALL_ERR_ARITHMETIC_OVERFLOW (-21) /* These syscall errors are unique to Firedancer and do not have an Agave equivalent. */ -#define FD_VM_SYSCALL_ERR_INSTR_ERR (-22) #define FD_VM_SYSCALL_ERR_INVALID_PDA (-23) /* the computed pda was not a valid ed25519 point */ #define FD_VM_SYSCALL_ERR_COMPUTE_BUDGET_EXCEEDED (-24) /* compute unit limit exceeded in syscall */ #define FD_VM_SYSCALL_ERR_SEGFAULT (-25) /* illegal memory address (e.g. read/write to an address not backed by any memory) in syscall */ diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c b/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c index 518f36b4ba..63c17361fc 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c @@ -1,16 +1,17 @@ #include "fd_vm_syscall.h" #include "../../runtime/program/fd_vote_program.h" -#include "../../runtime/sysvar/fd_sysvar.h" -#include "../../runtime/sysvar/fd_sysvar_clock.h" -#include "../../runtime/sysvar/fd_sysvar_epoch_rewards.h" -#include "../../runtime/sysvar/fd_sysvar_epoch_schedule.h" -#include "../../runtime/sysvar/fd_sysvar_rent.h" -#include "../../runtime/sysvar/fd_sysvar_last_restart_slot.h" #include "../../runtime/context/fd_exec_txn_ctx.h" #include "../../runtime/context/fd_exec_instr_ctx.h" #include "../../runtime/fd_system_ids.h" #include "fd_vm_syscall_macros.h" +/* FIXME: In the original version of this code, there was an FD_TEST + to check if the VM was attached to an instruction context (that + would have crashed anyway because of pointer chasing). If the VM + is being run outside the Solana runtime, it should never invoke + this syscall in the first place. So we treat this as a SIGCALL in + a non-crashing way for the time being. */ + int fd_vm_syscall_sol_get_clock_sysvar( /**/ void * _vm, /**/ ulong out_vaddr, @@ -19,15 +20,7 @@ fd_vm_syscall_sol_get_clock_sysvar( /**/ void * _vm, FD_PARAM_UNUSED ulong r4, FD_PARAM_UNUSED ulong r5, /**/ ulong * _ret ) { - fd_vm_t * vm = (fd_vm_t *)_vm; - - /* FIXME: In the original version of this code, there was an FD_TEST - to check if the VM was attached to an instruction context (that - would have crashed anyway because of pointer chasing). If the VM - is being run outside the Solana runtime, it should never invoke - this syscall in the first place. So we treat this as a SIGCALL in - a non-crashing way. */ - + fd_vm_t * vm = _vm; fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx; if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME; @@ -43,14 +36,8 @@ fd_vm_syscall_sol_get_clock_sysvar( /**/ void * _vm, fd_vm_haddr_query_t * queries[] = { &var_query }; FD_VM_TRANSLATE_MUT( vm, queries ); - fd_sol_sysvar_clock_t const * clock = fd_sysvar_clock_read( instr_ctx->txn_ctx->funk, - instr_ctx->txn_ctx->funk_txn, - instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !clock ) ) { - FD_LOG_ERR(( "failed to read sysvar clock" )); - } - - memcpy( var_query.haddr, clock, sizeof(fd_sol_sysvar_clock_t) ); + fd_sol_sysvar_clock_t clock = fd_sysvar_clock_read_nofail( instr_ctx->sysvar_cache ); + memcpy( var_query.haddr, &clock, sizeof(fd_sol_sysvar_clock_t) ); *_ret = 0UL; return FD_VM_SUCCESS; @@ -64,15 +51,7 @@ fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/ void * _vm, FD_PARAM_UNUSED ulong r4, FD_PARAM_UNUSED ulong r5, /**/ ulong * _ret ) { - fd_vm_t * vm = (fd_vm_t *)_vm; - - /* FIXME: In the original version of this code, there was an FD_TEST - to check if the VM was attached to an instruction context (that - would have crashed anyway because of pointer chasing). If the VM - is being run outside the Solana runtime, it should never invoke - this syscall in the first place. So we treat this as a SIGCALL in - a non-crashing way for the time being. */ - + fd_vm_t * vm = _vm; fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx; if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME; @@ -88,14 +67,8 @@ fd_vm_syscall_sol_get_epoch_schedule_sysvar( /**/ void * _vm, fd_vm_haddr_query_t * queries[] = { &var_query }; FD_VM_TRANSLATE_MUT( vm, queries ); - fd_epoch_schedule_t * schedule = fd_sysvar_epoch_schedule_read( instr_ctx->txn_ctx->funk, - instr_ctx->txn_ctx->funk_txn, - instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( schedule == NULL ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch schedule" )); - } - - memcpy( var_query.haddr, schedule, sizeof(fd_epoch_schedule_t) ); + fd_epoch_schedule_t schedule = fd_sysvar_epoch_schedule_read_nofail( instr_ctx->sysvar_cache ); + memcpy( var_query.haddr, &schedule, sizeof(fd_epoch_schedule_t) ); *_ret = 0UL; return FD_VM_SUCCESS; @@ -109,15 +82,7 @@ fd_vm_syscall_sol_get_rent_sysvar( /**/ void * _vm, FD_PARAM_UNUSED ulong r4, FD_PARAM_UNUSED ulong r5, /**/ ulong * _ret ) { - fd_vm_t * vm = (fd_vm_t *)_vm; - - /* FIXME: In the original version of this code, there was an FD_TEST - to check if the VM was attached to an instruction context (that - would have crashed anyway because of pointer chasing). If the VM - is being run outside the Solana runtime, it should never invoke - this syscall in the first place. So we treat this as a SIGCALL in - a non-crashing way for the time being. */ - + fd_vm_t * vm = _vm; fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx; if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME; @@ -133,20 +98,14 @@ fd_vm_syscall_sol_get_rent_sysvar( /**/ void * _vm, fd_vm_haddr_query_t * queries[] = { &var_query }; FD_VM_TRANSLATE_MUT( vm, queries ); - fd_rent_t const * rent = fd_sysvar_rent_read( instr_ctx->txn_ctx->funk, - instr_ctx->txn_ctx->funk_txn, - instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !rent ) ) { - FD_LOG_ERR(( "failed to read sysvar rent" )); - } - - memcpy( var_query.haddr, rent, sizeof(fd_rent_t) ); + fd_rent_t rent = fd_sysvar_rent_read_nofail( instr_ctx->sysvar_cache ); + memcpy( var_query.haddr, &rent, sizeof(fd_rent_t) ); *_ret = 0UL; return FD_VM_SUCCESS; } -/* https://github.com/anza-xyz/agave/blob/36323b6dcd3e29e4d6fe6d73d716a3f33927148b/programs/bpf_loader/src/syscalls/sysvar.rs#L144 */ +/* https://github.com/anza-xyz/agave/blob/v2.3.2/programs/bpf_loader/src/syscalls/sysvar.rs#L149 */ int fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/ void * _vm, /**/ ulong out_vaddr, @@ -155,7 +114,9 @@ fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/ void * _vm, FD_PARAM_UNUSED ulong r4, FD_PARAM_UNUSED ulong r5, /**/ ulong * _ret ) { - fd_vm_t * vm = (fd_vm_t *)_vm; + fd_vm_t * vm = _vm; + fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx; + if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME; FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sol_sysvar_last_restart_slot_t) ) ); @@ -169,14 +130,13 @@ fd_vm_syscall_sol_get_last_restart_slot_sysvar( /**/ void * _vm, fd_vm_haddr_query_t * queries[] = { &var_query }; FD_VM_TRANSLATE_MUT( vm, queries ); - fd_sol_sysvar_last_restart_slot_t * last_restart_slot = fd_sysvar_last_restart_slot_read( vm->instr_ctx->txn_ctx->funk, - vm->instr_ctx->txn_ctx->funk_txn, - vm->instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !last_restart_slot ) ) { - FD_LOG_ERR(( "failed to read sysvar last restart slot" )); + fd_sol_sysvar_last_restart_slot_t last_restart_slot; + if( FD_UNLIKELY( !fd_sysvar_last_restart_slot_read( vm->instr_ctx->sysvar_cache, &last_restart_slot ) ) ) { + FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_ctx->instr_err_idx ); + return FD_VM_ERR_INVAL; } - memcpy( var_query.haddr, last_restart_slot, sizeof(fd_sol_sysvar_last_restart_slot_t) ); + memcpy( var_query.haddr, &last_restart_slot, sizeof(fd_sol_sysvar_last_restart_slot_t) ); *_ret = 0UL; return FD_VM_SUCCESS; @@ -191,7 +151,9 @@ fd_vm_syscall_sol_get_sysvar( /**/ void * _vm, /**/ ulong sz, FD_PARAM_UNUSED ulong r5, /**/ ulong * _ret ) { - fd_vm_t * vm = (fd_vm_t *)_vm; + fd_vm_t * vm = _vm; + fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx; + if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME; /* sysvar_id_cost seems to just always be 32 / 250 = 0... https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L190-L197 */ @@ -235,18 +197,16 @@ fd_vm_syscall_sol_get_sysvar( /**/ void * _vm, return FD_VM_SUCCESS; } - /* we know that the account data won't be changed for the lifetime of this view, because sysvars don't change inter-block */ - FD_TXN_ACCOUNT_DECL( sysvar_account ); - err = fd_txn_account_init_from_funk_readonly( sysvar_account, sysvar_id, vm->instr_ctx->txn_ctx->funk, vm->instr_ctx->txn_ctx->funk_txn ); - if( FD_UNLIKELY( err ) ) { + ulong sysvar_buf_len; + uchar const * sysvar_buf = + fd_sysvar_cache_data_query( vm->instr_ctx->sysvar_cache, sysvar_id, &sysvar_buf_len ); + if( FD_UNLIKELY( !sysvar_buf ) ) { *_ret = 2UL; return FD_VM_SUCCESS; } /* https://github.com/anza-xyz/agave/blob/v2.1.0/programs/bpf_loader/src/syscalls/sysvar.rs#L223-L228 Note the length check is at the very end to fail after performing sufficient checks. */ - const uchar * sysvar_buf = sysvar_account->vt->get_data( sysvar_account ); - ulong sysvar_buf_len = sysvar_account->vt->get_data_len( sysvar_account ); if( FD_UNLIKELY( offset_length>sysvar_buf_len ) ) { *_ret = 1UL; @@ -634,23 +594,21 @@ fd_vm_syscall_sol_get_epoch_rewards_sysvar( /**/ void * _vm, FD_PARAM_UNUSED ulong r4, FD_PARAM_UNUSED ulong r5, /**/ ulong * _ret ) { - fd_vm_t * vm = (fd_vm_t *)_vm; - + fd_vm_t * vm = _vm; fd_exec_instr_ctx_t const * instr_ctx = vm->instr_ctx; if( FD_UNLIKELY( !instr_ctx ) ) return FD_VM_SYSCALL_ERR_OUTSIDE_RUNTIME; FD_VM_CU_UPDATE( vm, fd_ulong_sat_add( FD_VM_SYSVAR_BASE_COST, sizeof(fd_sysvar_epoch_rewards_t) ) ); - void * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_REWARDS, sizeof(fd_sysvar_epoch_rewards_t) ); + uchar * out = FD_VM_MEM_HADDR_ST( vm, out_vaddr, FD_VM_ALIGN_RUST_SYSVAR_EPOCH_REWARDS, sizeof(fd_sysvar_epoch_rewards_t) ); - fd_sysvar_epoch_rewards_t const * epoch_rewards = fd_sysvar_epoch_rewards_read( instr_ctx->txn_ctx->funk, - instr_ctx->txn_ctx->funk_txn, - instr_ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !epoch_rewards ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); + fd_sysvar_epoch_rewards_t epoch_rewards; + if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( instr_ctx->sysvar_cache, &epoch_rewards ) ) ) { + FD_TXN_ERR_FOR_LOG_INSTR( vm->instr_ctx->txn_ctx, FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR, vm->instr_ctx->txn_ctx->instr_err_idx ); + return FD_VM_ERR_INVAL; } - - memcpy( out, epoch_rewards, sizeof(fd_sysvar_epoch_rewards_t) ); + memcpy( out, &epoch_rewards, sizeof(fd_sysvar_epoch_rewards_t) ); + memset( out+81, 0, 7 ); /* padding */ *_ret = 0UL; return FD_VM_SUCCESS; diff --git a/src/flamenco/vm/syscall/test_vm_syscall_curve.c b/src/flamenco/vm/syscall/test_vm_syscall_curve.c index f4ab0d4761..e7acb634c2 100644 --- a/src/flamenco/vm/syscall/test_vm_syscall_curve.c +++ b/src/flamenco/vm/syscall/test_vm_syscall_curve.c @@ -1,4 +1,5 @@ #include "fd_vm_syscall.h" +#include "../../runtime/context/fd_exec_slot_ctx.h" #include "../test_vm_util.h" static inline void set_memory_region( uchar * mem, ulong sz ) { for( ulong i=0UL; i