From d5bb9ba26ad9125630523ddf8d24f05e0eac09e1 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Mon, 21 Jul 2025 01:59:02 +0000 Subject: [PATCH 1/5] tile includes --- src/app/ledger/main.c | 1 - src/disco/archiver/fd_archiver_feeder.c | 2 +- src/disco/archiver/fd_archiver_playback.c | 2 +- src/disco/archiver/fd_archiver_writer.c | 2 +- src/disco/dedup/fd_dedup_tile.c | 6 ++---- src/disco/plugin/fd_plugin_tile.c | 2 +- src/disco/sign/fd_sign_tile.c | 2 +- src/discof/exec/fd_exec_tile.c | 3 ++- src/discof/writer/fd_writer_tile.c | 4 ++-- src/flamenco/runtime/fd_runtime.c | 16 +++++++++------- src/flamenco/runtime/fd_runtime.h | 6 +----- .../runtime/sysvar/fd_sysvar_recent_hashes.c | 12 +++++------- .../runtime/tests/harness/fd_elf_harness.c | 1 + .../runtime/tests/harness/fd_elf_harness.h | 2 -- src/flamenco/vm/test_vm_util.h | 1 + 15 files changed, 28 insertions(+), 34 deletions(-) diff --git a/src/app/ledger/main.c b/src/app/ledger/main.c index ebe8abaef4..7d75b025a1 100644 --- a/src/app/ledger/main.c +++ b/src/app/ledger/main.c @@ -1,6 +1,5 @@ #include "../../flamenco/types/fd_types.h" #include "../../flamenco/runtime/fd_rocksdb.h" -#include "../../flamenco/runtime/context/fd_capture_ctx.h" #include "../../flamenco/runtime/fd_blockstore.h" #include #include 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 13b117c93b..1d7091d8f7 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 548aa4b820..87b5bffd5e 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/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/plugin/fd_plugin_tile.c b/src/disco/plugin/fd_plugin_tile.c index e4ff3471e7..712a6b141a 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/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/discof/exec/fd_exec_tile.c b/src/discof/exec/fd_exec_tile.c index 0bc3aad348..78219c622d 100644 --- a/src/discof/exec/fd_exec_tile.c +++ b/src/discof/exec/fd_exec_tile.c @@ -1,7 +1,8 @@ -#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_public.h" diff --git a/src/discof/writer/fd_writer_tile.c b/src/discof/writer/fd_writer_tile.c index 8d6cb69938..1cb945985d 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" diff --git a/src/flamenco/runtime/fd_runtime.c b/src/flamenco/runtime/fd_runtime.c index aa84c8911a..b23863e94c 100644 --- a/src/flamenco/runtime/fd_runtime.c +++ b/src/flamenco/runtime/fd_runtime.c @@ -712,13 +712,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; diff --git a/src/flamenco/runtime/fd_runtime.h b/src/flamenco/runtime/fd_runtime.h index c054acf446..33291462b5 100644 --- a/src/flamenco/runtime/fd_runtime.h +++ b/src/flamenco/runtime/fd_runtime.h @@ -3,7 +3,6 @@ #include "stdarg.h" -#include "../fd_flamenco_base.h" #include "fd_runtime_err.h" #include "fd_runtime_init.h" #include "fd_rocksdb.h" @@ -11,9 +10,6 @@ #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" @@ -472,7 +468,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/sysvar/fd_sysvar_recent_hashes.c b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c index a085f936b7..f3da4cb95f 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c @@ -1,18 +1,16 @@ #include "fd_sysvar_recent_hashes.h" #include "../fd_acc_mgr.h" #include "fd_sysvar.h" -#include "../fd_runtime.h" #include "../fd_system_ids.h" +#include "../context/fd_exec_slot_ctx.h" /* 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 out_mem[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] ) { - fd_blockhashes_t const * bhq = fd_bank_block_hash_queue_query( slot_ctx->bank ); - +encode_rbh_from_blockhash_queue( fd_blockhashes_t const * bhq, + uchar out_mem[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] ) { ulong queue_sz = fd_blockhash_deq_cnt( bhq->d.deque ); ulong out_max = fd_ulong_min( queue_sz, FD_SYSVAR_RECENT_HASHES_CAP ); @@ -50,7 +48,7 @@ fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx, ulong sz = FD_SYSVAR_RECENT_HASHES_BINCODE_SZ; uchar * enc = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, sz ); fd_memset( enc, 0, sz ); - encode_rbh_from_blockhash_queue( slot_ctx, enc ); + encode_rbh_from_blockhash_queue( fd_bank_block_hash_queue_query( slot_ctx->bank ), 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; @@ -86,7 +84,7 @@ fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx, fd_spad_t * runti fd_memset( enc, 0, sz ); /* Encode the recent blockhashes */ - encode_rbh_from_blockhash_queue( slot_ctx, enc ); + encode_rbh_from_blockhash_queue( fd_bank_block_hash_queue_query( slot_ctx->bank ), enc ); /* Set the sysvar from the encoded data */ fd_sysvar_set( slot_ctx->bank, 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/vm/test_vm_util.h b/src/flamenco/vm/test_vm_util.h index 547e3edaa6..0a15a8d711 100644 --- a/src/flamenco/vm/test_vm_util.h +++ b/src/flamenco/vm/test_vm_util.h @@ -3,6 +3,7 @@ #include "fd_vm.h" #include "../runtime/context/fd_exec_instr_ctx.h" +#include "../runtime/context/fd_exec_slot_ctx.h" #include "../../util/valloc/fd_valloc.h" #define TEST_VM_REJECT_CALLX_R10_FEATURE_PREFIX (0x7e787d5c6d662d23) From c2c71d0f5bad8f353df3bd88f6774e80fd7c3ead Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Wed, 30 Jul 2025 12:18:33 +0000 Subject: [PATCH 2/5] runtime: sysvar cache v2 Refactor all stored sysvar accesses to use a write-through cache. Removes direct database accesses. Adds a few sysvar tests. --- src/disco/plugin/fd_plugin_tile.c | 3 +- src/discof/replay/fd_exec.c | 1 + src/discof/replay/fd_exec.h | 16 +- src/discof/replay/fd_replay_tile.c | 17 +- src/flamenco/fd_flamenco_base.h | 3 + src/flamenco/rewards/fd_rewards.c | 159 ++++--- .../runtime/context/fd_exec_instr_ctx.h | 8 +- .../runtime/context/fd_exec_slot_ctx.c | 43 +- .../runtime/context/fd_exec_slot_ctx.h | 7 - src/flamenco/runtime/fd_bank.c | 6 + src/flamenco/runtime/fd_bank.h | 2 + src/flamenco/runtime/fd_borrowed_account.c | 4 +- src/flamenco/runtime/fd_borrowed_account.h | 6 +- src/flamenco/runtime/fd_executor.c | 106 ++--- src/flamenco/runtime/fd_hashes.c | 39 +- src/flamenco/runtime/fd_hashes.h | 2 +- src/flamenco/runtime/fd_runtime.c | 168 +++---- src/flamenco/runtime/fd_runtime_init.c | 4 +- .../program/fd_address_lookup_table_program.c | 51 +- .../runtime/program/fd_bpf_loader_program.c | 39 +- .../runtime/program/fd_loader_v4_program.c | 18 +- .../runtime/program/fd_stake_program.c | 200 ++++---- .../runtime/program/fd_stake_program.h | 13 +- .../runtime/program/fd_system_program_nonce.c | 47 +- .../runtime/program/fd_vote_program.c | 141 +++--- .../runtime/program/test_program_cache.c | 11 +- src/flamenco/runtime/sysvar/Local.mk | 18 +- src/flamenco/runtime/sysvar/fd_sysvar.c | 48 +- src/flamenco/runtime/sysvar/fd_sysvar.h | 18 +- src/flamenco/runtime/sysvar/fd_sysvar_base.h | 44 ++ src/flamenco/runtime/sysvar/fd_sysvar_cache.c | 314 ++++++++++++ src/flamenco/runtime/sysvar/fd_sysvar_cache.h | 449 ++++++++++++++++++ .../runtime/sysvar/fd_sysvar_cache_db.c | 325 +++++++++++++ .../runtime/sysvar/fd_sysvar_cache_private.h | 160 +++++++ src/flamenco/runtime/sysvar/fd_sysvar_clock.c | 233 +++------ src/flamenco/runtime/sysvar/fd_sysvar_clock.h | 63 +-- .../runtime/sysvar/fd_sysvar_epoch_rewards.c | 62 +-- .../runtime/sysvar/fd_sysvar_epoch_rewards.h | 12 +- .../runtime/sysvar/fd_sysvar_epoch_schedule.c | 54 +-- .../runtime/sysvar/fd_sysvar_epoch_schedule.h | 24 +- .../runtime/sysvar/fd_sysvar_instructions.h | 1 - .../sysvar/fd_sysvar_last_restart_slot.c | 95 ++-- .../sysvar/fd_sysvar_last_restart_slot.h | 35 +- .../runtime/sysvar/fd_sysvar_recent_hashes.c | 104 +--- .../runtime/sysvar/fd_sysvar_recent_hashes.h | 47 +- src/flamenco/runtime/sysvar/fd_sysvar_rent.c | 59 +-- src/flamenco/runtime/sysvar/fd_sysvar_rent.h | 26 +- src/flamenco/runtime/sysvar/fd_sysvar_rent1.c | 13 - .../runtime/sysvar/fd_sysvar_slot_hashes.c | 158 +----- .../runtime/sysvar/fd_sysvar_slot_hashes.h | 62 +-- .../runtime/sysvar/fd_sysvar_slot_history.c | 269 ++++------- .../runtime/sysvar/fd_sysvar_slot_history.h | 84 +++- .../runtime/sysvar/fd_sysvar_stake_history.c | 87 ++-- .../runtime/sysvar/fd_sysvar_stake_history.h | 43 +- src/flamenco/runtime/sysvar/test_sysvar.c | 33 ++ .../runtime/sysvar/test_sysvar_cache.c | 45 ++ .../runtime/sysvar/test_sysvar_clock.c | 26 + .../sysvar/test_sysvar_epoch_rewards.c | 32 ++ .../sysvar/test_sysvar_epoch_schedule.c | 32 +- .../sysvar/test_sysvar_last_restart_slot.c | 22 + .../sysvar/test_sysvar_recent_hashes.bin | Bin 0 -> 6008 bytes .../sysvar/test_sysvar_recent_hashes.c | 23 + .../runtime/sysvar/test_sysvar_rent.c | 32 +- .../sysvar/test_sysvar_slot_hashes.bin | Bin 0 -> 20488 bytes .../runtime/sysvar/test_sysvar_slot_hashes.c | 23 + .../sysvar/test_sysvar_slot_history.bin | Bin 0 -> 131097 bytes .../runtime/sysvar/test_sysvar_slot_history.c | 23 + .../sysvar/test_sysvar_stake_history.bin | Bin 0 -> 16392 bytes .../sysvar/test_sysvar_stake_history.c | 23 + src/flamenco/runtime/tests/fd_dump_pb.c | 6 +- .../runtime/tests/harness/fd_block_harness.c | 25 +- .../runtime/tests/harness/fd_instr_harness.c | 100 ++-- .../runtime/tests/harness/fd_txn_harness.c | 116 ++--- .../runtime/tests/harness/fd_vm_harness.c | 5 +- src/flamenco/stakes/fd_stakes.c | 37 +- src/flamenco/stakes/fd_stakes.h | 1 - .../vm/syscall/fd_vm_syscall_runtime.c | 122 ++--- .../vm/syscall/test_vm_syscall_curve.c | 1 + src/funk/fd_funk_base.h | 3 + 79 files changed, 2757 insertions(+), 1994 deletions(-) create mode 100644 src/flamenco/runtime/sysvar/fd_sysvar_base.h create mode 100644 src/flamenco/runtime/sysvar/fd_sysvar_cache.c create mode 100644 src/flamenco/runtime/sysvar/fd_sysvar_cache.h create mode 100644 src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c create mode 100644 src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h delete mode 100644 src/flamenco/runtime/sysvar/fd_sysvar_rent1.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_cache.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_clock.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_epoch_rewards.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_last_restart_slot.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.bin create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.bin create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_slot_history.bin create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_slot_history.c create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_stake_history.bin create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_stake_history.c diff --git a/src/disco/plugin/fd_plugin_tile.c b/src/disco/plugin/fd_plugin_tile.c index 712a6b141a..5580f08d4c 100644 --- a/src/disco/plugin/fd_plugin_tile.c +++ b/src/disco/plugin/fd_plugin_tile.c @@ -1,8 +1,7 @@ #include "../topo/fd_topo.h" - #include "generated/fd_plugin_tile_seccomp.h" - #include "../plugin/fd_plugin.h" +#include "../../flamenco/leaders/fd_leaders_base.h" #define IN_KIND_REPLAY (0) #define IN_KIND_GOSSIP (1) diff --git a/src/discof/replay/fd_exec.c b/src/discof/replay/fd_exec.c index c0958a0e86..8a3bbe3113 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 b5b5b189e5..60d95a43d8 100644 --- a/src/discof/replay/fd_exec.h +++ b/src/discof/replay/fd_exec.h @@ -19,17 +19,17 @@ generate_stake_weight_msg( fd_exec_slot_ctx_t * slot_ctx, /* This function needs to be completely rewritten for SIMD-0180. For now it's a hack that sends old data (pre SIMD-0180) in the new format. */ - fd_stake_weight_msg_t * stake_weight_msg = (fd_stake_weight_msg_t *)fd_type_pun( stake_weight_msg_out ); - fd_vote_stake_weight_t * stake_weights = stake_weight_msg->weights; - ulong staked_cnt = fd_stake_weights_by_node( vote_accounts, - stake_weights, - runtime_spad ); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); + fd_stake_weight_msg_t * stake_weight_msg = (fd_stake_weight_msg_t *)fd_type_pun( stake_weight_msg_out ); + fd_vote_stake_weight_t * stake_weights = stake_weight_msg->weights; + ulong staked_cnt = fd_stake_weights_by_node( vote_accounts, stake_weights, runtime_spad ); + + 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 = staked_cnt; - stake_weight_msg->start_slot = fd_epoch_slot0( epoch_schedule, stake_weight_msg_out[0] ); - stake_weight_msg->slot_cnt = epoch_schedule->slots_per_epoch; + stake_weight_msg->start_slot = fd_epoch_slot0( &epoch_schedule, stake_weight_msg_out[0] ); + stake_weight_msg->slot_cnt = epoch_schedule.slots_per_epoch; stake_weight_msg->excluded_stake = 0UL; stake_weight_msg->vote_keyed_lsched = (ulong)fd_runtime_should_use_vote_keyed_leader_schedule( slot_ctx->bank ); diff --git a/src/discof/replay/fd_replay_tile.c b/src/discof/replay/fd_replay_tile.c index 6bc7a40ded..04da7e5361 100644 --- a/src/discof/replay/fd_replay_tile.c +++ b/src/discof/replay/fd_replay_tile.c @@ -15,8 +15,8 @@ #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_ssmsg.h" @@ -296,14 +296,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, epoch_stakes, 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() ) ); @@ -318,7 +319,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, next_epoch_stakes, 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() ) ); @@ -788,10 +789,14 @@ init_after_snapshot( fd_replay_tile_ctx_t * ctx, static void init_from_snapshot( fd_replay_tile_ctx_t * ctx, fd_stem_context_t * stem ) { + if( FD_UNLIKELY( !fd_sysvar_cache_restore( ctx->slot_ctx ) ) ) { + FD_LOG_ERR(( "Failed to restore sysvar cache" )); + } 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_runtime_update_leaders( ctx->slot_ctx->bank, + fd_runtime_update_leaders( + ctx->slot_ctx->bank, fd_bank_slot_get( ctx->slot_ctx->bank ), ctx->runtime_spad ); 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 4257824e13..583d7a5b8d 100644 --- a/src/flamenco/rewards/fd_rewards.c +++ b/src/flamenco/rewards/fd_rewards.c @@ -1,13 +1,13 @@ #include "fd_rewards.h" #include +#include "../runtime/fd_acc_mgr.h" #include "../runtime/fd_executor_err.h" #include "../runtime/program/fd_vote_program.h" #include "../runtime/sysvar/fd_sysvar_epoch_rewards.h" #include "../runtime/sysvar/fd_sysvar_epoch_schedule.h" #include "../stakes/fd_stakes.h" #include "../runtime/program/fd_stake_program.h" -#include "../runtime/sysvar/fd_sysvar_stake_history.h" #include "../runtime/context/fd_capture_ctx.h" /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/sdk/src/inflation.rs#L85 */ @@ -41,49 +41,50 @@ 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; - - 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; - } +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( 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; - } else { - min_slot = 0; - } + ulong min_slot = fd_ulong_min( enable, devnet_and_testnet ); + if( min_slot == ULONG_MAX ) { + if( FD_FEATURE_ACTIVE_BANK( bank, pico_inflation ) ) { + min_slot = fd_bank_features_query( bank )->pico_inflation; + } else { + min_slot = 0; } - return min_slot; + } + return min_slot; } /* 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 @@ -262,23 +263,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 )); } @@ -353,10 +356,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, + 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 ) ) { @@ -391,7 +393,7 @@ calculate_stake_vote_rewards_account( fd_calculate_stake_vote_rewards_result_t * result, fd_spad_t * spad ) { - fd_epoch_info_pair_t const * stake_infos = temp_info->stake_infos; + fd_epoch_info_pair_t const * stake_infos = temp_info->stake_infos; FD_SPAD_FRAME_BEGIN( spad ) { @@ -555,10 +557,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, + 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 ) ) { @@ -639,9 +640,12 @@ calculate_validator_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_calculate_validator_rewards_result_t * result, fd_epoch_info_t * temp_info, 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 ); - if( FD_UNLIKELY( !stake_history ) ) { + /* 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" )); } @@ -670,6 +674,8 @@ calculate_validator_rewards( fd_exec_slot_ctx_t * slot_ctx, &result->calculate_stake_vote_rewards_result, temp_info, 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. @@ -748,7 +754,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 ); @@ -763,10 +769,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( slot_ctx->bank, stake_reward_calculation, @@ -928,13 +937,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_rewards_t * epoch_rewards = fd_bank_epoch_rewards_locking_modify( slot_ctx->bank ); +set_epoch_reward_status_inactive( fd_bank_t * bank ) { + fd_epoch_rewards_t * epoch_rewards = fd_bank_epoch_rewards_locking_modify( bank ); if( fd_epoch_rewards_is_active( epoch_rewards ) ) { FD_LOG_NOTICE(( "Done partitioning rewards for current epoch" )); } fd_epoch_rewards_set_active( epoch_rewards, 0 ); - fd_bank_epoch_rewards_end_locking_modify( slot_ctx->bank ); + fd_bank_epoch_rewards_end_locking_modify( bank ); } /* Sets the epoch reward status to active. @@ -1008,10 +1017,10 @@ fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, ulong distribution_starting_block_height = fd_epoch_rewards_get_starting_block_height( epoch_rewards ); ulong distribution_end_exclusive = fd_epoch_rewards_get_exclusive_ending_block_height( epoch_rewards ); - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( slot_ctx->bank ); - ulong epoch = fd_bank_epoch_get( slot_ctx->bank ); + 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 ) <= fd_epoch_rewards_get_num_partitions( epoch_rewards ) ) ) { + if( FD_UNLIKELY( get_slots_in_epoch( epoch, &epoch_schedule ) <= fd_epoch_rewards_get_num_partitions( epoch_rewards ) ) ) { FD_LOG_CRIT(( "Should not be distributing rewards" )); } @@ -1038,7 +1047,7 @@ fd_distribute_partitioned_epoch_rewards( fd_exec_slot_ctx_t * slot_ctx, /* 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 ); + set_epoch_reward_status_inactive( slot_ctx->bank ); fd_sysvar_epoch_rewards_set_inactive( slot_ctx ); } } @@ -1093,10 +1102,11 @@ void fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_capture_ctx_t * capture_ctx, fd_spad_t * runtime_spad ) { - fd_sysvar_epoch_rewards_t epoch_rewards[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, epoch_rewards ) ) ) { + 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; } @@ -1114,19 +1124,21 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, 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( slot, - slot_ctx->funk, - slot_ctx->funk_txn, - 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" )); } @@ -1154,7 +1166,6 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, fd_accumulate_stake_infos( slot_ctx, stakes, - stake_history, new_warmup_cooldown_rate_epoch, &_accumulator, &epoch_info, @@ -1195,6 +1206,6 @@ fd_rewards_recalculate_partitioned_rewards( fd_exec_slot_ctx_t * slot_ctx, /* Update the epoch reward status with the newly re-calculated partitions. */ set_epoch_reward_status_active( slot_ctx, epoch_rewards->distribution_starting_block_height ); } else { - set_epoch_reward_status_inactive( slot_ctx ); + set_epoch_reward_status_inactive( slot_ctx->bank ); } } diff --git a/src/flamenco/runtime/context/fd_exec_instr_ctx.h b/src/flamenco/runtime/context/fd_exec_instr_ctx.h index 9a06a9c760..2430e49620 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; @@ -12,9 +13,10 @@ typedef struct fd_borrowed_account fd_borrowed_account_t; instruction (program invocation). */ 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 */ + 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 beeac1f64b..09d32d391c 100644 --- a/src/flamenco/runtime/context/fd_exec_slot_ctx.c +++ b/src/flamenco/runtime/context/fd_exec_slot_ctx.c @@ -1,5 +1,5 @@ #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" @@ -184,6 +184,11 @@ fd_exec_slot_ctx_recover( fd_exec_slot_ctx_t * slot_ctx, fd_bank_stakes_end_locking_modify( slot_ctx->bank ); + /* Rent: Must be recovered before any other sysvars, since the rent + settings determine the min balance of other sysvar accounts. */ + + fd_sysvar_rent_write_cache_only( slot_ctx, &old_bank->rent_collector.rent ); + /* Index vote accounts */ /* Block Hash Queue */ @@ -298,11 +303,7 @@ 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 ); - - /* Rent */ - - fd_bank_rent_set( slot_ctx->bank, old_bank->rent_collector.rent ); + fd_sysvar_epoch_schedule_write_cache_only( slot_ctx, &old_bank->epoch_schedule ); /* Last Restart Slot */ @@ -313,26 +314,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 ); @@ -605,9 +590,3 @@ fd_exec_slot_ctx_recover_status_cache( fd_exec_slot_ctx_t * ctx, } FD_SPAD_FRAME_END; return ctx; } - -ulong -fd_bank_epoch_get( fd_bank_t const * bank ) { - fd_epoch_schedule_t epoch_schedule = fd_bank_epoch_schedule_get( bank ); - return fd_slot_to_epoch( &epoch_schedule, fd_bank_slot_get( bank ), NULL ); -} 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/fd_bank.c b/src/flamenco/runtime/fd_bank.c index 09dee1f63f..3ed22b4f31 100644 --- a/src/flamenco/runtime/fd_bank.c +++ b/src/flamenco/runtime/fd_bank.c @@ -792,3 +792,9 @@ fd_banks_rekey_root_bank( fd_banks_t * banks, ulong slot ) { return bank; } + +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 3b8fb58e9d..aa1b30239e 100644 --- a/src/flamenco/runtime/fd_bank.h +++ b/src/flamenco/runtime/fd_bank.h @@ -8,6 +8,7 @@ #include "../fd_rwlock.h" #include "fd_runtime_const.h" #include "fd_blockhashes.h" +#include "sysvar/fd_sysvar_cache.h" FD_PROTOTYPES_BEGIN @@ -181,6 +182,7 @@ FD_PROTOTYPES_BEGIN X(fd_epoch_schedule_t, epoch_schedule, sizeof(fd_epoch_schedule_t), alignof(fd_epoch_schedule_t), 0, 0, 0 ) /* Epoch schedule */ \ X(fd_rent_t, rent, sizeof(fd_rent_t), alignof(fd_rent_t), 0, 0, 0 ) /* Rent */ \ X(fd_slot_lthash_t, lthash, sizeof(fd_slot_lthash_t), alignof(fd_slot_lthash_t), 0, 0, 0 ) /* LTHash */ \ + X(fd_sysvar_cache_t, sysvar_cache, sizeof(fd_sysvar_cache_t), alignof(fd_sysvar_cache_t), 0, 0, 0 ) /* Sysvar cache */ \ X(fd_vote_accounts_global_t, next_epoch_stakes, 200000000UL, 128UL, 1, 0, 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 */ \ 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_executor.c b/src/flamenco/runtime/fd_executor.c index 6e26d7662b..9637a6f29b 100644 --- a/src/flamenco/runtime/fd_executor.c +++ b/src/flamenco/runtime/fd_executor.c @@ -1,14 +1,12 @@ #include "fd_executor.h" #include "fd_acc_mgr.h" +#include "fd_bank.h" #include "fd_hashes.h" #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" #include "program/fd_address_lookup_table_program.h" #include "program/fd_bpf_loader_program.h" @@ -21,11 +19,9 @@ #include "program/fd_builtin_programs.h" #include "program/fd_vote_program.h" #include "program/fd_zk_elgamal_proof_program.h" -#include "program/fd_bpf_program_util.h" -#include "sysvar/fd_sysvar_slot_history.h" +#include "sysvar/fd_sysvar_cache.h" #include "sysvar/fd_sysvar_epoch_schedule.h" #include "sysvar/fd_sysvar_instructions.h" -#include "sysvar/fd_sysvar_slot_hashes.h" #include "sysvar/fd_sysvar_rent.h" #include "tests/fd_dump_pb.h" @@ -318,33 +314,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 ) { @@ -519,11 +488,13 @@ load_transaction_account( fd_exec_txn_ctx_t * txn_ctx, /* https://github.com/anza-xyz/agave/blob/v2.3.1/svm/src/account_loader.rs#L828-L835 */ 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_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( txn_ctx->bank ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( sysvar_cache ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail ( 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 fd_ulong_sat_add( base_account_size, acct->vt->get_data_len( acct ) ); @@ -552,12 +523,7 @@ static int fd_executor_load_transaction_accounts_old( fd_exec_txn_ctx_t * txn_ctx ) { ulong requested_loaded_accounts_data_size = txn_ctx->compute_budget_details.loaded_accounts_data_size_limit; - fd_epoch_schedule_t schedule[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( txn_ctx->funk, txn_ctx->funk_txn, schedule ) ) ) { - FD_LOG_ERR(( "Unable to read and decode epoch schedule sysvar" )); - } - - ulong epoch = fd_slot_to_epoch( schedule, txn_ctx->slot, NULL ); + ulong const epoch = fd_bank_epoch_get( txn_ctx->bank ); /* https://github.com/anza-xyz/agave/blob/v2.2.0/svm/src/account_loader.rs#L429-L443 */ for( ushort i=0; iaccounts_cnt; i++ ) { @@ -786,10 +752,7 @@ fd_collect_loaded_account( fd_exec_txn_ctx_t * txn_ctx, https://github.com/anza-xyz/agave/blob/v2.3.1/svm/src/account_loader.rs#L550-L689 */ static int fd_executor_load_transaction_accounts_simd_186( fd_exec_txn_ctx_t * txn_ctx ) { - fd_epoch_schedule_t schedule[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( txn_ctx->funk, txn_ctx->funk_txn, schedule ) ) ) { - FD_LOG_ERR(( "Unable to read and decode epoch schedule sysvar" )); - } + fd_epoch_schedule_t schedule[1] = { fd_sysvar_epoch_schedule_read_nofail( fd_bank_sysvar_cache_query( txn_ctx->bank ) ) }; ulong epoch = fd_slot_to_epoch( schedule, txn_ctx->slot, NULL ); @@ -1021,14 +984,17 @@ fd_executor_validate_transaction_fee_payer( fd_exec_txn_ctx_t * txn_ctx ) { return FD_RUNTIME_TXN_ERR_ACCOUNT_NOT_FOUND; } + fd_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( txn_ctx->bank ); + fd_epoch_schedule_t const epoch_schedule = fd_sysvar_epoch_schedule_read_nofail( sysvar_cache ); + fd_rent_t const rent = fd_sysvar_rent_read_nofail ( 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 */ @@ -1043,7 +1009,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; } @@ -1080,21 +1046,21 @@ 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_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( txn_ctx->bank ); + fd_slot_hash_t const * slot_hashes = fd_sysvar_slot_hashes_join_const( 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( 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; @@ -1308,6 +1274,7 @@ fd_execute_instr_end( fd_exec_instr_ctx_t * instr_ctx, int fd_execute_instr( fd_exec_txn_ctx_t * txn_ctx, fd_instr_info_t * instr ) { + fd_sysvar_cache_t const * sysvar_cache = fd_bank_sysvar_cache_query( txn_ctx->bank ); FD_RUNTIME_TXN_SPAD_FRAME_BEGIN( txn_ctx->spad, txn_ctx ) { int instr_exec_result = fd_instr_stack_push( txn_ctx, instr ); if( FD_UNLIKELY( instr_exec_result ) ) { @@ -1320,8 +1287,9 @@ fd_execute_instr( fd_exec_txn_ctx_t * txn_ctx, https://github.com/anza-xyz/agave/blob/v2.2.12/program-runtime/src/invoke_context.rs#L512-L619 */ fd_exec_instr_ctx_t * ctx = &txn_ctx->instr_stack[ txn_ctx->instr_stack_sz - 1 ]; *ctx = (fd_exec_instr_ctx_t) { - .instr = instr, - .txn_ctx = txn_ctx, + .instr = instr, + .txn_ctx = txn_ctx, + .sysvar_cache = sysvar_cache, }; fd_base58_encode_32( txn_ctx->accounts[ instr->program_id ].pubkey->uc, NULL, ctx->program_id_base58 ); @@ -1648,7 +1616,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( fd_bank_sysvar_cache_query( txn_ctx->bank ) ); ulong starting_lamports_l = 0; ulong starting_lamports_h = 0; @@ -1673,7 +1641,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 ) ) { @@ -1683,7 +1651,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 ) { @@ -1693,8 +1661,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 */ @@ -1707,8 +1675,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_hashes.c b/src/flamenco/runtime/fd_hashes.c index e0309201fa..591b6a2efd 100644 --- a/src/flamenco/runtime/fd_hashes.c +++ b/src/flamenco/runtime/fd_hashes.c @@ -139,19 +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 ) { - 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_calculate_epoch_accounts_hash_values( fd_bank_t * bank ) { + ulong const 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; @@ -163,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 b23863e94c..f2df6a94da 100644 --- a/src/flamenco/runtime/fd_runtime.c +++ b/src/flamenco/runtime/fd_runtime.c @@ -9,31 +9,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 +38,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 @@ -139,25 +124,20 @@ fd_runtime_update_leaders( fd_bank_t * bank, ulong slot, fd_spad_t * runtime_spad ) { - FD_SPAD_FRAME_BEGIN( runtime_spad ) { - - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( 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_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_SPAD_FRAME_BEGIN( runtime_spad ) { 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 ); @@ -209,7 +189,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 ) ) { @@ -244,7 +224,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 ); @@ -282,9 +261,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 ); @@ -325,8 +304,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 )); } @@ -437,7 +419,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 ); @@ -460,7 +442,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 ) ); @@ -510,16 +492,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 ); } FD_SPAD_FRAME_END; @@ -1042,7 +1024,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 ) ) { @@ -1638,12 +1620,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, @@ -1700,14 +1678,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 = { @@ -2078,11 +2052,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 ); } @@ -2113,9 +2089,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 */ @@ -2130,12 +2106,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, - 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; } @@ -2166,7 +2142,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_const( sysvar_cache ); if( FD_UNLIKELY( !history ) ) { FD_LOG_ERR(( "StakeHistory sysvar could not be read and decoded" )); } @@ -2178,6 +2154,9 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx, &temp_info, runtime_spad ); + fd_sysvar_stake_history_leave_const( sysvar_cache, history ); + history = NULL; + /* Distribute rewards */ fd_hash_t parent_blockhash = {0}; @@ -2201,10 +2180,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) */ + /* Update current leaders using slot_ctx->slot_bank.epoch_stakes (new T-2 stakes) */ fd_runtime_update_leaders( slot_ctx->bank, 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" )); @@ -2245,20 +2224,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; } @@ -2312,12 +2288,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_rent_init( slot_ctx ); + fd_sysvar_slot_hashes_init( slot_ctx ); fd_sysvar_stake_history_init( slot_ctx ); fd_sysvar_last_restart_slot_init( slot_ctx ); @@ -2339,9 +2313,9 @@ 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 ); @@ -2623,7 +2597,7 @@ fd_runtime_process_genesis_block( fd_exec_slot_ctx_t * slot_ctx, fd_runtime_update_leaders( slot_ctx->bank, 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 ); @@ -2875,12 +2849,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 ); 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..ad4192e4af 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,10 @@ 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] = { fd_sysvar_rent_read_nofail( ctx->sysvar_cache ) }; + 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 +866,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 +986,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 +1111,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 +1130,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 4eb7316d45..7d49fecbdc 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" @@ -731,8 +730,8 @@ common_extend_program( fd_exec_instr_ctx_t * instr_ctx, } /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1434-L1437 */ - 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_sol_sysvar_clock_t clock[1]; + if( FD_UNLIKELY( !fd_sysvar_clock_read( instr_ctx->sysvar_cache, clock ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } ulong clock_slot = clock->slot; @@ -787,10 +786,10 @@ common_extend_program( fd_exec_instr_ctx_t * instr_ctx, } /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/lib.rs#L1480-L1485 */ - 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 @@ -1066,7 +1065,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; } @@ -1088,7 +1088,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; @@ -1109,8 +1109,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; } @@ -1929,7 +1930,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; } @@ -2043,7 +2045,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_loader_v4_program.c b/src/flamenco/runtime/program/fd_loader_v4_program.c index 0b3ff21c11..af16817352 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 ad278b57e9..6eae743828 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. @@ -280,9 +279,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 = @@ -746,19 +745,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_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 epoch_schedule[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( funk, funk_txn, epoch_schedule ) ) ) { + + 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; @@ -828,14 +831,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->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 @@ -1139,30 +1142,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->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 @@ -1183,13 +1191,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->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 @@ -1622,9 +1630,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}; @@ -1951,13 +1959,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}; @@ -2551,12 +2558,12 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { If the sysvar exists, check the `active` field */ int epoch_rewards_active = 0; - - fd_sysvar_epoch_rewards_t epoch_rewards[1]; - if( FD_LIKELY( fd_sysvar_epoch_rewards_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, epoch_rewards ) ) ) { - epoch_rewards_active = epoch_rewards->active; + { + fd_sysvar_epoch_rewards_t epoch_rewards[1]; + if( fd_sysvar_epoch_rewards_read( ctx->sysvar_cache, epoch_rewards ) ) { + epoch_rewards_active = epoch_rewards->active; + } } - 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; @@ -2590,7 +2597,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 @@ -2620,7 +2628,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 ) ) @@ -2665,7 +2674,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; @@ -2707,13 +2717,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; @@ -2722,13 +2734,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; } @@ -2778,19 +2791,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; } @@ -2815,13 +2832,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; @@ -2832,15 +2851,16 @@ 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->features, - &new_rate_activation_epoch, - &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; // 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, @@ -2852,6 +2872,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; @@ -2872,7 +2893,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 @@ -2898,7 +2920,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 @@ -2943,7 +2966,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}; @@ -2973,7 +2997,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 ) ) @@ -3026,7 +3051,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) ) ) @@ -3084,9 +3110,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 ); @@ -3127,9 +3153,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 c1f468fcf9..7dcd45cfa5 100644 --- a/src/flamenco/runtime/program/fd_stake_program.h +++ b/src/flamenco/runtime/program/fd_stake_program.h @@ -17,12 +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_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 44531f59dd..1cc964e0f9 100644 --- a/src/flamenco/runtime/program/fd_system_program_nonce.c +++ b/src/flamenco/runtime/program/fd_system_program_nonce.c @@ -2,10 +2,9 @@ #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" static int @@ -27,38 +26,32 @@ require_acct( fd_exec_instr_ctx_t * ctx, static int require_acct_rent( fd_exec_instr_ctx_t * ctx, ushort idx, - fd_rent_t const ** out_rent ) { + fd_rent_t * out_rent ) { do { int err = require_acct( ctx, idx, &fd_sysvar_rent_id ); 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 ); - if( FD_UNLIKELY( !rent ) ) + if( FD_UNLIKELY( !fd_sysvar_rent_read( ctx->sysvar_cache, out_rent ) ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; - *out_rent = rent; return FD_EXECUTOR_INSTR_SUCCESS; } 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_t const * rbh = fd_sysvar_recent_hashes_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, ctx->txn_ctx->spad ); - if( FD_UNLIKELY( !rbh ) ) { + if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( ctx->sysvar_cache ) ) ) { return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; } - (*out)->hashes = rbh->hashes; - return FD_EXECUTOR_INSTR_SUCCESS; } @@ -268,18 +261,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( fd_blockhash_deq_empty( fd_bank_block_hash_queue_query( ctx->txn_ctx->bank )->d.deque ) ) ) { 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,16 +469,14 @@ 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); /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_processor.rs#L450 */ - fd_rent_t const * rent = NULL; + fd_rent_t rent; do { int err = require_acct_rent( ctx, 3UL, &rent ); if( FD_UNLIKELY( err ) ) return err; @@ -497,7 +484,7 @@ 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#L451-L460 */ - return fd_system_program_withdraw_nonce_account( ctx, requested_lamports, rent ); + return fd_system_program_withdraw_nonce_account( ctx, requested_lamports, &rent ); } /* https://github.com/solana-labs/solana/blob/v1.17.23/programs/system/src/system_instruction.rs#L153-L198 @@ -633,18 +620,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( fd_blockhash_deq_empty( fd_bank_block_hash_queue_query( ctx->txn_ctx->bank )->d.deque ) ) ) { 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; @@ -652,7 +635,7 @@ 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#L479 */ - fd_rent_t const * rent = NULL; + fd_rent_t rent; do { err = require_acct_rent( ctx, 2UL, &rent ); if( FD_UNLIKELY( err ) ) return err; @@ -660,7 +643,7 @@ 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#L480 */ - err = fd_system_program_initialize_nonce_account( ctx, &account, authorized, rent ); + err = fd_system_program_initialize_nonce_account( ctx, &account, authorized, &rent ); /* Implicit drop */ diff --git a/src/flamenco/runtime/program/fd_vote_program.c b/src/flamenco/runtime/program/fd_vote_program.c index 75330eb509..fc15c435b3 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], @@ -1989,7 +1986,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, @@ -2025,7 +2022,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], @@ -2160,7 +2157,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 */ @@ -2248,7 +2246,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 }; @@ -2368,7 +2368,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 ) < @@ -2378,7 +2379,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 @@ -2406,7 +2408,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 @@ -2519,13 +2522,18 @@ 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 epoch_schedule[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( ctx->txn_ctx->funk, ctx->txn_ctx->funk_txn, epoch_schedule ) ) ) + 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 ); - if( FD_UNLIKELY( !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; + } // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L145 rc = update_commission( &me, @@ -2575,21 +2583,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; } @@ -2630,21 +2637,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; } @@ -2694,20 +2700,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; } @@ -2727,18 +2732,21 @@ 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 ); + FD_TEST( slot_hashes ); rc = process_tower_sync( &me, slot_hashes, clock, tower_sync, signers, ctx ); + fd_sysvar_slot_hashes_leave_const( ctx->sysvar_cache, slot_hashes ); + break; } @@ -2755,10 +2763,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; @@ -2805,7 +2815,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 2e3ed99942..b88089b6a8 100644 --- a/src/flamenco/runtime/program/test_program_cache.c +++ b/src/flamenco/runtime/program/test_program_cache.c @@ -300,14 +300,21 @@ main( int argc, test_slot_ctx->bank = bank; test_slot_ctx->banks = banks; - fd_epoch_schedule_t epoch_schedule = { + fd_rent_t const rent = { + .lamports_per_uint8_year = 3480, + .exemption_threshold = 2, + .burn_percent = 50 + }; + fd_sysvar_rent_write( test_slot_ctx, &rent ); + + 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..9b5827b906 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_sysvar_cache_db,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_base.h b/src/flamenco/runtime/sysvar/fd_sysvar_base.h new file mode 100644 index 0000000000..215a2711da --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_base.h @@ -0,0 +1,44 @@ +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_base_h +#define HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_base_h + +#include "../../fd_flamenco_base.h" + +#define FD_SYSVAR_ALIGN_MAX (16UL) + +#define FD_SYSVAR_CLOCK_BINCODE_SZ ( 40UL) +#define FD_SYSVAR_CLOCK_ALIGN ( 8UL) +#define FD_SYSVAR_CLOCK_FOOTPRINT ( 40UL) + +#define FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ ( 81UL) +/* FD_SYSVAR_EPOCH_REWARDS_ALIGN provided by fd_types.h (16UL) */ +#define FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT ( 96UL) + +#define FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ ( 33UL) +#define FD_SYSVAR_EPOCH_SCHEDULE_ALIGN ( 8UL) +#define FD_SYSVAR_EPOCH_SCHEDULE_FOOTPRINT ( 40UL) + +#define FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ (8UL) +#define FD_SYSVAR_LAST_RESTART_SLOT_ALIGN (8UL) +#define FD_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT (8UL) + +#define FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ( 6008UL) /* Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/recent_blockhashes.rs#L157 */ +#define FD_SYSVAR_RECENT_HASHES_ALIGN ( 8UL) +#define FD_SYSVAR_RECENT_HASHES_FOOTPRINT ( 6088UL) + +#define FD_SYSVAR_RENT_BINCODE_SZ ( 17UL) +#define FD_SYSVAR_RENT_ALIGN ( 8UL) +#define FD_SYSVAR_RENT_FOOTPRINT ( 24UL) + +#define FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ( 20488UL) /* Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/slot_hashes.rs#L69 */ +#define FD_SYSVAR_SLOT_HASHES_ALIGN ( 8UL) +#define FD_SYSVAR_SLOT_HASHES_FOOTPRINT ( 20528UL) + +#define FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ (131097UL) /* 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_ALIGN ( 8UL) +#define FD_SYSVAR_SLOT_HISTORY_FOOTPRINT (131120UL) + +#define FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ( 16392UL) /* 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_ALIGN ( 8UL) +#define FD_SYSVAR_STAKE_HISTORY_FOOTPRINT ( 16408UL) + +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_base_h */ 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..d5083e4484 --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache.c @@ -0,0 +1,314 @@ +#include "fd_sysvar_cache.h" +#include "fd_sysvar_cache_private.h" +#include "../context/fd_exec_slot_ctx.h" +#include + +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, alignof(fd_sysvar_cache_t) ) ) ) { + FD_LOG_WARNING(( "misaligned mem" )); + return NULL; + } + + fd_sysvar_cache_t * sysvar_cache = mem; + sysvar_cache->magic = 0UL; + memset( sysvar_cache->desc, 0, FD_SYSVAR_CACHE_ENTRY_CNT*sizeof(fd_sysvar_desc_t) ); + + 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 This is a good place to ref-count writable joins */ + 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, alignof(fd_sysvar_cache_t) ) ) ) { + 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; +} + +uchar const * +fd_sysvar_cache_data_query( + fd_sysvar_cache_t const * sysvar_cache, + void const * address, /* 32 bytes */ + ulong * psz +) { + *psz = 0UL; + fd_pubkey_t const pubkey = FD_LOAD( fd_pubkey_t, address ); + sysvar_tbl_t const * entry = sysvar_map_query( &pubkey, NULL ); + if( FD_UNLIKELY( !entry ) ) return NULL; /* address is not a sysvar */ + fd_sysvar_desc_t const * desc = &sysvar_cache->desc[ entry->desc_idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl [ entry->desc_idx ]; + if( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) return NULL; /* sysvar data invalid */ + *psz = desc->data_sz; + return (uchar const *)sysvar_cache + pos->data_off; +} + +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 +) { + ulong _dummy[1]; + if( !opt_sz ) opt_sz = _dummy; + if( !opt_sz_max ) opt_sz_max = _dummy; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + fd_pubkey_t const pubkey = FD_LOAD( fd_pubkey_t, address ); + 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_desc_t * desc = &cache->desc [ entry->desc_idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ entry->desc_idx ]; + desc->flags &= ~FD_SYSVAR_FLAG_VALID; + desc->flags |= FD_SYSVAR_FLAG_WRITE_LOCK; + *opt_sz = desc->data_sz; + *opt_sz_max = fd_sysvar_pos_tbl[ entry->desc_idx ].data_max; + return (uchar *)cache + pos->data_off; +} + +/* Generate accessors for sysvars that are backed by POD structs. */ + +#define SIMPLE_SYSVAR_READ( name, name2, typet ) \ + typet * \ + fd_sysvar_##name##_read( fd_sysvar_cache_t const * cache, \ + typet * out ) { \ + ulong const idx = FD_SYSVAR_##name##_IDX; \ + fd_sysvar_desc_t const * desc = &cache->desc[ idx ]; \ + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; \ + if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_VALID ) ) ) return NULL; \ + memcpy( out, (uchar *)cache+pos->obj_off, pos->obj_max ); \ + return out; \ + } + +#define SIMPLE_SYSVAR( name, name2, type ) \ + SIMPLE_SYSVAR_READ( name, name2, fd_##type##_t ) +FD_SYSVAR_SIMPLE_ITER( SIMPLE_SYSVAR ) +#undef SIMPLE_SYSVAR +#undef SIMPLE_SYSVAR_READ + +fd_block_block_hash_entry_t * /* deque */ +fd_sysvar_recent_hashes_join( + fd_exec_slot_ctx_t * slot_ctx +) { + ulong const idx = FD_SYSVAR_recent_hashes_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( cache ) ) ) return NULL; + FD_VOLATILE( cache->desc[ idx ].flags ) = FD_SYSVAR_FLAG_WRITE_LOCK; /* FIXME consider CAS */ + cache->desc[ idx ].data_sz = 0U; + fd_recent_block_hashes_global_t * rbh = (void *)cache->obj_recent_hashes; + fd_block_block_hash_entry_t * deq = deq_fd_block_block_hash_entry_t_join( (uchar *)rbh+rbh->hashes_offset ); + /* If the above is_valid check is passed, then join is guaranteed to succeed */ + if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "recent blockhashes sysvar corruption detected" )); + return deq; +} + +fd_block_block_hash_entry_t const * /* deque */ +fd_sysvar_recent_hashes_join_const( + fd_sysvar_cache_t const * cache +) { + if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( cache ) ) ) return NULL; + fd_recent_block_hashes_global_t * var = (void *)cache->obj_recent_hashes; + fd_block_block_hash_entry_t * deq = deq_fd_block_block_hash_entry_t_join( (uchar *)var+var->hashes_offset ); + if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "recent blockhashes sysvar corruption detected" )); + return deq; /* demote to const ptr */ +} + +void +fd_sysvar_recent_hashes_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_block_block_hash_entry_t const * hashes_deque +) { + (void)sysvar_cache; (void)hashes_deque; +} + +fd_slot_hash_t * +fd_sysvar_slot_hashes_join( + fd_exec_slot_ctx_t * slot_ctx +) { + ulong const idx = FD_SYSVAR_slot_hashes_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_slot_hashes_is_valid( cache ) ) ) return NULL; + FD_VOLATILE( cache->desc[ idx ].flags ) = FD_SYSVAR_FLAG_WRITE_LOCK; /* FIXME consider CAS */ + cache->desc[ idx ].data_sz = 0U; + fd_slot_hashes_global_t * var = (void *)cache->obj_slot_hashes; + fd_slot_hash_t * deq = deq_fd_slot_hash_t_join( (uchar *)var+var->hashes_offset ); + /* If the above is_valid check is passed, then join is guaranteed to succeed */ + if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "slot hashes sysvar corruption detected" )); + return deq; +} + +fd_slot_hash_t const * +fd_sysvar_slot_hashes_join_const( + fd_sysvar_cache_t const * cache +) { + if( FD_UNLIKELY( !fd_sysvar_slot_hashes_is_valid( cache ) ) ) return NULL; + fd_slot_hashes_global_t * var = (void *)cache->obj_slot_hashes; + fd_slot_hash_t * deq = deq_fd_slot_hash_t_join( (uchar *)var+var->hashes_offset ); + /* If the above is_valid check is passed, then join is guaranteed to succeed */ + if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "slot hashes sysvar corruption detected" )); + return deq; /* demote to const ptr */ +} + +void +fd_sysvar_slot_hashes_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_slot_hash_t const * slot_hashes +) { + (void)sysvar_cache; (void)slot_hashes; +} + +fd_slot_history_global_t * +fd_sysvar_slot_history_join( + fd_exec_slot_ctx_t * slot_ctx +) { + ulong const idx = FD_SYSVAR_slot_history_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_slot_history_is_valid( cache ) ) ) return NULL; + FD_VOLATILE( cache->desc[ idx ].flags ) = FD_SYSVAR_FLAG_WRITE_LOCK; /* FIXME consider CAS */ + cache->desc[ idx ].data_sz = 0U; + return (void *)cache->obj_slot_history; +} + +fd_slot_history_global_t const * +fd_sysvar_slot_history_join_const( + fd_sysvar_cache_t const * cache +) { + if( FD_UNLIKELY( !fd_sysvar_slot_history_is_valid( cache ) ) ) return NULL; + return (void const *)( cache->obj_slot_history ); +} + +void +fd_sysvar_slot_history_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_slot_history_global_t const * slot_history +) { + (void)sysvar_cache; (void)slot_history; +} + +fd_stake_history_t * +fd_sysvar_stake_history_join( + fd_exec_slot_ctx_t * slot_ctx +) { + ulong const idx = FD_SYSVAR_stake_history_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( cache ) ) ) return NULL; + FD_VOLATILE( cache->desc[ idx ].flags ) = FD_SYSVAR_FLAG_WRITE_LOCK; /* FIXME consider CAS */ + cache->desc[ idx ].data_sz = 0U; + return (void *)cache->obj_stake_history; +} + +fd_stake_history_t const * +fd_sysvar_stake_history_join_const( + fd_sysvar_cache_t const * cache +) { + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( cache ) ) ) return NULL; + return (void const *)cache->obj_stake_history; +} + +void +fd_sysvar_stake_history_leave_const( + fd_sysvar_cache_t const * sysvar_cache, + fd_stake_history_t const * stake_history +) { + (void)sysvar_cache; (void)stake_history; +} + +int +fd_sysvar_obj_restore( fd_sysvar_cache_t * cache, + fd_sysvar_desc_t * desc, + fd_sysvar_pos_t const * pos, + int log_fails ) { + desc->flags &= ~FD_SYSVAR_FLAG_VALID; + + uchar const * data = (uchar const *)cache + pos->data_off; + ulong const data_sz = desc->data_sz; + + if( FD_UNLIKELY( !pos->obj_max ) ) { + /* Sysvar is directly stored - does not need to be deserialized */ + desc->flags |= FD_SYSVAR_FLAG_VALID; + FD_LOG_DEBUG(( "Restored sysvar %s (data_sz=%lu)", pos->name, data_sz )); + return 0; + } + + fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+data_sz }; + ulong obj_sz = 0UL; + if( FD_UNLIKELY( pos->decode_footprint( &ctx, &obj_sz )!=FD_BINCODE_SUCCESS ) ) { + if( log_fails ) { + FD_LOG_DEBUG(( "Failed to decode sysvar %s with data_sz=%lu: decode failed", + pos->name, data_sz )); + } + return EINVAL; + } + if( FD_UNLIKELY( obj_sz > pos->obj_max ) ) { + if( log_fails ) { + FD_LOG_WARNING(( "Failed to restore sysvar %s: obj_sz=%lu exceeds max=%u", + pos->name, obj_sz, pos->obj_max )); + } + return ENOMEM; + } + pos->decode( (uchar *)cache+pos->obj_off, &ctx ); + desc->flags |= FD_SYSVAR_FLAG_VALID; + + FD_LOG_DEBUG(( "Restored sysvar %s (data_sz=%lu obj_sz=%lu)", + pos->name, data_sz, obj_sz )); + return 0; +} 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..38547fbc4a --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache.h @@ -0,0 +1,449 @@ +#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 "fd_sysvar_base.h" +#include "../../types/fd_types.h" + +#define FD_SYSVAR_CACHE_ENTRY_CNT 9 + +/* 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. fd_sysvar_cache_desc_t points either form. + + 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_desc { + uint flags; + uint data_sz; +}; + +typedef struct fd_sysvar_desc fd_sysvar_desc_t; + +#define FD_SYSVAR_FLAG_VALID (0x1u) +#define FD_SYSVAR_FLAG_WRITE_LOCK (0x2u) + +struct fd_sysvar_cache { + ulong magic; /* ==FD_SYSVAR_CACHE_MAGIC */ + + fd_sysvar_desc_t desc[ FD_SYSVAR_CACHE_ENTRY_CNT ]; + + uchar bin_clock [ FD_SYSVAR_CLOCK_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_clock [ FD_SYSVAR_CLOCK_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_epoch_rewards [ FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_epoch_rewards [ FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_epoch_schedule [ FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_epoch_schedule [ FD_SYSVAR_EPOCH_SCHEDULE_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_recent_hashes [ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_recent_hashes [ FD_SYSVAR_RECENT_HASHES_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_rent [ FD_SYSVAR_RENT_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_rent [ FD_SYSVAR_RENT_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_slot_hashes [ FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_slot_hashes [ FD_SYSVAR_SLOT_HASHES_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_slot_history [ FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_slot_history [ FD_SYSVAR_SLOT_HISTORY_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar bin_stake_history [ FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); + uchar obj_stake_history [ FD_SYSVAR_STAKE_HISTORY_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); +}; + +typedef struct fd_sysvar_cache fd_sysvar_cache_t; + +#define FD_SYSVAR_clock_IDX 0 +#define FD_SYSVAR_epoch_rewards_IDX 1 +#define FD_SYSVAR_epoch_schedule_IDX 2 +#define FD_SYSVAR_last_restart_slot_IDX 3 +#define FD_SYSVAR_recent_hashes_IDX 4 +#define FD_SYSVAR_rent_IDX 5 +#define FD_SYSVAR_slot_hashes_IDX 6 +#define FD_SYSVAR_slot_history_IDX 7 +#define FD_SYSVAR_stake_history_IDX 8 + +FD_PROTOTYPES_BEGIN + +/* Constructor API */ + +/* 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_restore rebuilds the sysvar cache from the account + database. Does blocking account database queries. Returns 1 on + success, or 0 on failure (logs warnings). Reasons for failure + include unexpected database error or sysvar deserialize failure. */ + +int +fd_sysvar_cache_restore( 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 +); + +#define FD_SYSVAR_IS_VALID( sysvar_cache, sysvar ) \ + ( ( FD_VOLATILE_CONST( sysvar_cache->desc[ FD_SYSVAR_##sysvar##_IDX ].flags ) \ + & ( FD_SYSVAR_FLAG_VALID|FD_SYSVAR_FLAG_WRITE_LOCK ) ) \ + == FD_SYSVAR_FLAG_VALID ) + +/* 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_IS_VALID( sysvar_cache, clock ); +} + +fd_sol_sysvar_clock_t * +fd_sysvar_clock_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_sol_sysvar_clock_t * out +); + +/* Macro to improve FD_LOG_ERR line number accuracy */ + +#define SIMPLE_SYSVAR_READ_NOFAIL( cache, name, typet ) \ + __extension__({ \ + typet out; \ + if( FD_UNLIKELY( !fd_sysvar_##name##_read( (cache), &out ) ) ) \ + FD_LOG_ERR(( "fd_sysvar_" #name "_read_nofail failed: sysvar not valid" )); \ + out; \ + }) + +#define fd_sysvar_clock_read_nofail( cache ) \ + SIMPLE_SYSVAR_READ_NOFAIL( cache, clock, fd_sol_sysvar_clock_t ) + +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_IS_VALID( sysvar_cache, epoch_rewards ); +} + +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_IS_VALID( sysvar_cache, epoch_schedule ); +} + +fd_epoch_schedule_t * +fd_sysvar_epoch_schedule_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_epoch_schedule_t * out +); + +#define fd_sysvar_epoch_schedule_read_nofail( cache ) \ + SIMPLE_SYSVAR_READ_NOFAIL( cache, epoch_schedule, fd_epoch_schedule_t ) + +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_IS_VALID( sysvar_cache, last_restart_slot ); +} + +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_IS_VALID( sysvar_cache, rent ); +} + +fd_rent_t * +fd_sysvar_rent_read( + fd_sysvar_cache_t const * sysvar_cache, + fd_rent_t * out +); + +#define fd_sysvar_rent_read_nofail( cache ) \ + SIMPLE_SYSVAR_READ_NOFAIL( cache, rent, fd_rent_t ) + +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_IS_VALID( sysvar_cache, recent_hashes ); +} + +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_exec_slot_ctx_t * slot_ctx, + 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_IS_VALID( sysvar_cache, slot_hashes ); +} + +fd_slot_hash_t * +fd_sysvar_slot_hashes_join( + fd_exec_slot_ctx_t * slot_ctx +); + +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_exec_slot_ctx_t * slot_ctx, + 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_IS_VALID( sysvar_cache, slot_history ); +} + +fd_slot_history_global_t * +fd_sysvar_slot_history_join( + fd_exec_slot_ctx_t * slot_ctx +); + +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_exec_slot_ctx_t * slot_ctx, + 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_IS_VALID( sysvar_cache, stake_history ); +} + +fd_stake_history_t * +fd_sysvar_stake_history_join( + fd_exec_slot_ctx_t * slot_ctx +); + +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_exec_slot_ctx_t * slot_ctx, + 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 +); + +/* The one exception where the sysvar cache diverges from the database + is when loading a snapshot. The epoch_schedule and rent sysvars are + read from the cache before accounts are restored. */ + +void +fd_sysvar_epoch_schedule_write_cache_only( + fd_exec_slot_ctx_t * slot_ctx, + fd_epoch_schedule_t const * epoch_schedule +); + +void +fd_sysvar_rent_write_cache_only( + fd_exec_slot_ctx_t * slot_ctx, + fd_rent_t const * rent +); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_cache_h */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c b/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c new file mode 100644 index 0000000000..3915830626 --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c @@ -0,0 +1,325 @@ +/* fd_sysvar_cache_db.c contains database interactions between the + sysvar cache and the account database. */ + +#include "fd_sysvar_base.h" +#include "fd_sysvar_cache.h" +#include "fd_sysvar_cache_private.h" +#include "fd_sysvar_rent.h" +#include "../context/fd_exec_slot_ctx.h" +#include "../fd_txn_account.h" +#include "../fd_acc_mgr.h" +#include "../fd_system_ids.h" +#include + +static int +sysvar_data_fill( fd_sysvar_cache_t * cache, + fd_exec_slot_ctx_t * slot_ctx, + ulong idx, + int log_fails ) { + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; + fd_pubkey_t const * key = &fd_sysvar_key_tbl[ idx ]; + fd_sysvar_desc_t * desc = &cache->desc [ idx ]; + + /* Read account from database */ + fd_funk_t * funk = slot_ctx->funk; + fd_funk_txn_t * funk_txn = slot_ctx->funk_txn; + FD_TXN_ACCOUNT_DECL( rec ); + int err = fd_txn_account_init_from_funk_readonly( rec, key, funk, funk_txn ); + if( err==FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) { + if( log_fails ) FD_LOG_DEBUG(( "Sysvar %s not found", pos->name )); + return 0; + } else if( err!=FD_ACC_MGR_SUCCESS ) { + FD_LOG_ERR(( "fd_txn_account_init_from_funk_readonly failed: %i", err )); + return EIO; + } + + /* Work around instruction fuzzer quirk */ + if( FD_UNLIKELY( rec->vt->get_lamports( rec )==0 ) ) { + if( log_fails ) FD_LOG_WARNING(( "Skipping sysvar %s: zero balance", pos->name )); + return 0; + } + + /* Fill data cache entry */ + ulong const data_sz = rec->vt->get_data_len( rec ); + if( FD_UNLIKELY( data_sz > pos->data_max ) ) { + if( log_fails ) { + FD_LOG_WARNING(( "Failed to restore sysvar %s: data_sz=%lu exceeds max=%u", + pos->name, data_sz, pos->data_max )); + } + return ENOMEM; + } + uchar * data = (uchar *)cache+pos->data_off; + fd_memcpy( data, rec->vt->get_data( rec ), data_sz ); + desc->data_sz = (uint)data_sz; + + /* Recover object cache entry from data cache entry */ + return fd_sysvar_obj_restore( cache, desc, pos, log_fails ); +} + +int +fd_sysvar_cache_restore( fd_exec_slot_ctx_t * slot_ctx ) { + + fd_sysvar_cache_t * cache = fd_sysvar_cache_join( fd_sysvar_cache_new( + fd_bank_sysvar_cache_modify( slot_ctx->bank ) ) ); + + int saw_err = 0; + for( ulong i=0UL; ibank ) ); + ulong const min_bal = fd_rent_exempt_minimum_balance( &rent, sz ); + + FD_TXN_ACCOUNT_DECL( rec ); + fd_txn_account_init_from_funk_mutable( rec, address, slot_ctx->funk, slot_ctx->funk_txn, 1, sz ); + + ulong const slot = fd_bank_slot_get( slot_ctx->bank ); + ulong const lamports_before = rec->vt->get_lamports( rec ); + ulong const lamports_after = fd_ulong_max( lamports_before, min_bal ); + rec->vt->set_lamports( rec, lamports_after ); + rec->vt->set_owner ( rec, &fd_sysvar_owner_id ); + rec->vt->set_slot ( rec, slot ); + rec->vt->set_data( rec, data, sz ); + + ulong lamports_minted; + if( FD_UNLIKELY( __builtin_usubl_overflow( lamports_after, lamports_before, &lamports_minted ) ) ) { + char name[ FD_BASE58_ENCODED_32_SZ ]; fd_base58_encode_32( address->uc, NULL, name ); + FD_LOG_CRIT(( "fd_sysvar_account_update: lamports overflowed: address=%s lamports_before=%lu lamports_after=%lu", + name, lamports_before, lamports_after )); + } + + if( lamports_minted ) { + ulong cap = fd_bank_capitalization_get( slot_ctx->bank ); + fd_bank_capitalization_set( slot_ctx->bank, cap+lamports_minted ); + } else if( lamports_before==lamports_after ) { + /* no balance change */ + } else { + __builtin_unreachable(); + } + + fd_txn_account_mutable_fini( rec, slot_ctx->funk, slot_ctx->funk_txn ); + + FD_LOG_DEBUG(( "Updated sysvar: address=%s data_sz=%lu slot=%lu lamports=%lu lamports_minted=%lu", + FD_BASE58_ENC_32_ALLOCA( address ), sz, slot, lamports_after, lamports_minted )); +} + +static void +sysvar_write_through( fd_exec_slot_ctx_t * slot_ctx, + fd_sysvar_cache_t * cache, + ulong const idx, + ulong const min_sz ) { + fd_sysvar_desc_t * desc = &cache->desc[ idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; + fd_bincode_encode_ctx_t ctx = {0}; + void * obj = (void *)( (ulong)cache + pos->obj_off ); + uchar * data = (uchar *)cache + pos->data_off; + ctx.data = data; + ctx.dataend = data + pos->data_max; + if( FD_UNLIKELY( pos->encode( obj, &ctx )!=FD_BINCODE_SUCCESS ) ) { + FD_LOG_CRIT(( "Failed to encode sysvar" )); + } + ulong data_sz = (ulong)ctx.data - (ulong)data; + if( data_szflags = FD_SYSVAR_FLAG_VALID; + desc->data_sz = (uint)data_sz; + + /* Already setting the valid flag here to fix the chicken-and-egg + problem where the rent sysvar has to meet rent-exemption when it is + first written. */ + + fd_pubkey_t const * addr = &fd_sysvar_key_tbl[ idx ]; + fd_sysvar_account_update( slot_ctx, addr, data, data_sz ); +} + +void +fd_sysvar_cache_data_modify_commit( + fd_exec_slot_ctx_t * slot_ctx, + void const * address, /* 32 bytes */ + ulong sz +) { + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + + /* Lookup sysvar entry */ + fd_pubkey_t pubkey; memcpy( pubkey.uc, address, 32UL ); + sysvar_tbl_t const * entry = sysvar_map_query( &pubkey, NULL ); + if( FD_UNLIKELY( !entry ) ) FD_LOG_CRIT(( "invalid sysvar_cache_data_modify_commit" )); + + /* Persist write to data cache and database */ + ulong const idx = entry->desc_idx; + fd_sysvar_desc_t * desc = &cache->desc [ idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; + fd_pubkey_t const * key = &fd_sysvar_key_tbl[ idx ]; + uchar * data = (uchar *)cache + pos->data_off; + if( FD_UNLIKELY( !( desc->flags & FD_SYSVAR_FLAG_WRITE_LOCK ) ) ) FD_LOG_CRIT(( "unmatched sysvar_cache_data_modify_commit" )); + if( FD_UNLIKELY( sz > pos->data_max ) ) FD_LOG_CRIT(( "attempted to write oversize sysvar (sz=%lu max=%u)", sz, pos->data_max )); + desc->data_sz = (uint)sz; + fd_sysvar_account_update( slot_ctx, key, data, sz ); + + /* Recover object cache entry from data cache entry */ + int err = fd_sysvar_obj_restore( cache, desc, pos, 1 ); + + desc->flags &= ~FD_SYSVAR_FLAG_WRITE_LOCK; + if( FD_UNLIKELY( err ) ) { + FD_LOG_ERR(( "Failed to modify sysvar bytes: could not recover typed representation (%d-%s)", errno, fd_io_strerror( errno ) )); + } +} + +/* All sysvar cache API functions that write (using above functions) + These are split into a separate compile units to allow unit tests to + build cleanly without a dependency on database symbols. */ + +#define SIMPLE_SYSVAR_WRITE( name, name2, typet, type ) \ + void \ + fd_sysvar_##name##_write( fd_exec_slot_ctx_t * slot_ctx, \ + typet const * name2 ) { \ + ulong const idx = FD_SYSVAR_##name##_IDX; \ + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); \ + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; \ + typet * buf = (void *)( (ulong)cache+pos->obj_off ); \ + *buf = *name2; \ + sysvar_write_through( slot_ctx, cache, idx, 0UL ); \ + } + +#define SIMPLE_SYSVAR( name, name2, type ) \ + SIMPLE_SYSVAR_WRITE( name, name2, fd_##type##_t, type ) +FD_SYSVAR_SIMPLE_ITER( SIMPLE_SYSVAR ) +#undef SIMPLE_SYSVAR + +void +fd_sysvar_recent_hashes_leave( + fd_exec_slot_ctx_t * slot_ctx, + fd_block_block_hash_entry_t * hashes +) { + ulong const idx = FD_SYSVAR_recent_hashes_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( FD_VOLATILE_CONST( cache->desc[ idx ].flags )!=FD_SYSVAR_FLAG_WRITE_LOCK ) ) { + FD_LOG_CRIT(( "unmatched sysvar leave" )); + } + fd_recent_block_hashes_global_t const * var = (void *)cache->obj_recent_hashes; + if( FD_UNLIKELY( !hashes || + (ulong)deq_fd_block_block_hash_entry_t_leave( hashes ) != + (ulong)var+var->hashes_offset ) ) { + FD_LOG_CRIT(( "sysvar leave called with invalid pointer" )); + } + sysvar_write_through( slot_ctx, cache, idx, 0UL ); +} + +void +fd_sysvar_slot_hashes_leave( + fd_exec_slot_ctx_t * slot_ctx, + fd_slot_hash_t * slot_hashes +) { + ulong const idx = FD_SYSVAR_slot_hashes_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( FD_VOLATILE_CONST( cache->desc[ idx ].flags )!=FD_SYSVAR_FLAG_WRITE_LOCK ) ) { + FD_LOG_CRIT(( "unmatched sysvar leave" )); + } + fd_slot_hashes_global_t const * var = (void *)cache->obj_slot_hashes; + if( FD_UNLIKELY( !slot_hashes || + (ulong)deq_fd_slot_hash_t_leave( slot_hashes ) != + (ulong)var+var->hashes_offset ) ) { + FD_LOG_CRIT(( "sysvar leave called with invalid pointer" )); + } + sysvar_write_through( slot_ctx, cache, idx, FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); +} + +void +fd_sysvar_slot_history_leave( + fd_exec_slot_ctx_t * slot_ctx, + fd_slot_history_global_t * slot_history +) { + ulong const idx = FD_SYSVAR_slot_history_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( FD_VOLATILE_CONST( cache->desc[ idx ].flags )!=FD_SYSVAR_FLAG_WRITE_LOCK ) ) { + FD_LOG_CRIT(( "unmatched sysvar leave" )); + } + if( FD_UNLIKELY( !slot_history ) ) { + FD_LOG_CRIT(( "sysvar leave called with invalid pointer" )); + } + sysvar_write_through( slot_ctx, cache, idx, FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ ); +} + +void +fd_sysvar_stake_history_leave( + fd_exec_slot_ctx_t * slot_ctx, + fd_stake_history_t * stake_history +) { + ulong const idx = FD_SYSVAR_stake_history_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( FD_VOLATILE_CONST( cache->desc[ idx ].flags )!=FD_SYSVAR_FLAG_WRITE_LOCK ) ) { + FD_LOG_CRIT(( "unmatched sysvar leave" )); + } + if( FD_UNLIKELY( !stake_history ) ) { + FD_LOG_CRIT(( "sysvar leave called with invalid pointer" )); + } + sysvar_write_through( slot_ctx, cache, idx, FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ); +} + +void +fd_sysvar_epoch_schedule_write_cache_only( + fd_exec_slot_ctx_t * slot_ctx, + fd_epoch_schedule_t const * epoch_schedule +) { + ulong const idx = FD_SYSVAR_epoch_schedule_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + fd_sysvar_desc_t * desc = &cache->desc [ idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; + fd_epoch_schedule_t * buf = (void *)( (ulong)cache+pos->obj_off ); + *buf = *epoch_schedule; + + fd_bincode_encode_ctx_t ctx = {0}; + uchar * data = (uchar *)cache + pos->data_off; + ctx.data = data; + ctx.dataend = data + pos->data_max; + if( FD_UNLIKELY( pos->encode( epoch_schedule, &ctx )!=FD_BINCODE_SUCCESS ) ) { + FD_LOG_CRIT(( "Failed to encode sysvar" )); + } + ulong data_sz = (ulong)ctx.data - (ulong)data; + + desc->flags = FD_SYSVAR_FLAG_VALID; + desc->data_sz = (uint)data_sz; +} + +void +fd_sysvar_rent_write_cache_only( + fd_exec_slot_ctx_t * slot_ctx, + fd_rent_t const * rent +) { + ulong const idx = FD_SYSVAR_rent_IDX; + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + fd_sysvar_desc_t * desc = &cache->desc [ idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; + fd_rent_t * buf = (void *)( (ulong)cache+pos->obj_off ); + *buf = *rent; + + fd_bincode_encode_ctx_t ctx = {0}; + uchar * data = (uchar *)cache + pos->data_off; + ctx.data = data; + ctx.dataend = data + pos->data_max; + if( FD_UNLIKELY( pos->encode( rent, &ctx )!=FD_BINCODE_SUCCESS ) ) { + FD_LOG_CRIT(( "Failed to encode sysvar" )); + } + ulong data_sz = (ulong)ctx.data - (ulong)data; + + desc->flags = FD_SYSVAR_FLAG_VALID; + desc->data_sz = (uint)data_sz; +} 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..a7ca4d2c7d --- /dev/null +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h @@ -0,0 +1,160 @@ +#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" +#include "../fd_system_ids_pp.h" + +#define FD_SYSVAR_CACHE_MAGIC (0x1aa5ecb2a49b600aUL) /* random number */ + +#define FD_SYSVAR_SIMPLE_ITER( SIMPLE_SYSVAR ) \ +SIMPLE_SYSVAR( clock, CLOCK, sol_sysvar_clock ) \ +SIMPLE_SYSVAR( epoch_rewards, EPOCH_REWARDS, sysvar_epoch_rewards ) \ +SIMPLE_SYSVAR( epoch_schedule, EPOCH_SCHEDULE, epoch_schedule ) \ +SIMPLE_SYSVAR( last_restart_slot, LAST_RESTART_SLOT, sol_sysvar_last_restart_slot ) \ +SIMPLE_SYSVAR( rent, RENT, rent ) + +/* Declare a perfect hash table mapping sysvar IDs to sysvar cache slots + Hashes bytes [8,12) of each sysvar address. */ + +struct sysvar_lut { + fd_pubkey_t key; + uchar desc_idx; +}; +typedef struct sysvar_lut 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 ) +#define MAP_PERFECT_0 MAP_SYSVAR( SYSVAR_CLOCK_ID, FD_SYSVAR_clock_IDX ) +#define MAP_PERFECT_1 MAP_SYSVAR( SYSVAR_SLOT_HIST_ID, FD_SYSVAR_slot_history_IDX ) +#define MAP_PERFECT_2 MAP_SYSVAR( SYSVAR_SLOT_HASHES_ID, FD_SYSVAR_slot_hashes_IDX ) +#define MAP_PERFECT_3 MAP_SYSVAR( SYSVAR_EPOCH_SCHED_ID, FD_SYSVAR_epoch_schedule_IDX ) +#define MAP_PERFECT_4 MAP_SYSVAR( SYSVAR_RECENT_BLKHASH_ID, FD_SYSVAR_recent_hashes_IDX ) +#define MAP_PERFECT_5 MAP_SYSVAR( SYSVAR_RENT_ID, FD_SYSVAR_rent_IDX ) +#define MAP_PERFECT_6 MAP_SYSVAR( SYSVAR_EPOCH_REWARDS_ID, FD_SYSVAR_epoch_rewards_IDX ) +#define MAP_PERFECT_7 MAP_SYSVAR( SYSVAR_STAKE_HIST_ID, FD_SYSVAR_stake_history_IDX ) +#define MAP_PERFECT_8 MAP_SYSVAR( SYSVAR_LAST_RESTART_ID, FD_SYSVAR_last_restart_slot_IDX ) +#include "../../../util/tmpl/fd_map_perfect.c" +#undef PERFECT_HASH + +/* Declare a table giving the buffer offsets and sizes of sysvars in the + cache. */ + +struct fd_sysvar_pos { + /* Offsets relative to start of sysvar cache */ + uint data_off; /* Raw data offset */ + uint obj_off; /* Typed object offset */ + uint data_max; + uint obj_max; + + char const * name; + + int (* decode_footprint)( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); + void (* decode)( void * mem, fd_bincode_decode_ctx_t * ctx ); + int (* encode)( void const * self, fd_bincode_encode_ctx_t * ctx ); +}; +typedef struct fd_sysvar_pos fd_sysvar_pos_t; + +#define TYPES_CALLBACKS( name, suf ) \ + .decode_footprint = fd_##name##_decode_footprint, \ + .decode = (__typeof__(((fd_sysvar_pos_t *)NULL)->decode))(ulong)fd_##name##_decode##suf, \ + .encode = (__typeof__(((fd_sysvar_pos_t *)NULL)->encode))(ulong)fd_##name##_encode##suf + +static fd_sysvar_pos_t const fd_sysvar_pos_tbl[ FD_SYSVAR_CACHE_ENTRY_CNT ] = { + [FD_SYSVAR_clock_IDX] = + { .name="clock", + .data_off=offsetof(fd_sysvar_cache_t, bin_clock ), .data_max=FD_SYSVAR_CLOCK_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_clock ), .obj_max =FD_SYSVAR_CLOCK_FOOTPRINT, + TYPES_CALLBACKS( sol_sysvar_clock, ) }, + [FD_SYSVAR_epoch_rewards_IDX] = + { .name="epoch rewards", + .data_off=offsetof(fd_sysvar_cache_t, bin_epoch_rewards ), .data_max=FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_epoch_rewards ), .obj_max =FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT, + TYPES_CALLBACKS( sysvar_epoch_rewards, ) }, + [FD_SYSVAR_epoch_schedule_IDX] = + { .name="epoch schedule", + .data_off=offsetof(fd_sysvar_cache_t, bin_epoch_schedule ), .data_max=FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_epoch_schedule ), .obj_max =FD_SYSVAR_EPOCH_SCHEDULE_FOOTPRINT, + TYPES_CALLBACKS( epoch_schedule, ) }, + [FD_SYSVAR_last_restart_slot_IDX] = + { .name="last restart slot", + .data_off=offsetof(fd_sysvar_cache_t, bin_last_restart_slot), .data_max=FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_last_restart_slot), .obj_max =FD_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT, + TYPES_CALLBACKS( sol_sysvar_last_restart_slot, ) }, + [FD_SYSVAR_recent_hashes_IDX] = + { .name="recent blockhashes", + .data_off=offsetof(fd_sysvar_cache_t, bin_recent_hashes ), .data_max=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_recent_hashes ), .obj_max =FD_SYSVAR_RECENT_HASHES_FOOTPRINT, + TYPES_CALLBACKS( recent_block_hashes, _global ) }, + [FD_SYSVAR_rent_IDX] = + { .name="rent", + .data_off=offsetof(fd_sysvar_cache_t, bin_rent ), .data_max=FD_SYSVAR_RENT_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_rent ), .obj_max =FD_SYSVAR_RENT_FOOTPRINT, + TYPES_CALLBACKS( rent, ) }, + [FD_SYSVAR_slot_hashes_IDX] = + { .name="slot hashes", + .data_off=offsetof(fd_sysvar_cache_t, bin_slot_hashes ), .data_max=FD_SYSVAR_SLOT_HASHES_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_slot_hashes ), .obj_max =FD_SYSVAR_SLOT_HASHES_FOOTPRINT, + TYPES_CALLBACKS( slot_hashes, _global ) }, + [FD_SYSVAR_slot_history_IDX] = + { .name="slot history", + .data_off=offsetof(fd_sysvar_cache_t, bin_slot_history ), .data_max=FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_slot_history ), .obj_max =FD_SYSVAR_SLOT_HISTORY_FOOTPRINT, + TYPES_CALLBACKS( slot_history, _global ) }, + [FD_SYSVAR_stake_history_IDX] = + { .name="stake history", + .data_off=offsetof(fd_sysvar_cache_t, bin_stake_history ), .data_max=FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ, + .obj_off =offsetof(fd_sysvar_cache_t, obj_stake_history ), .obj_max =FD_SYSVAR_STAKE_HISTORY_FOOTPRINT, + TYPES_CALLBACKS( stake_history, ) }, +}; + +#undef TYPES_CALLBACKS + +static fd_pubkey_t const fd_sysvar_key_tbl[ FD_SYSVAR_CACHE_ENTRY_CNT ] = { + [ FD_SYSVAR_clock_IDX ] = {{ SYSVAR_CLOCK_ID }}, + [ FD_SYSVAR_epoch_rewards_IDX ] = {{ SYSVAR_EPOCH_REWARDS_ID }}, + [ FD_SYSVAR_epoch_schedule_IDX ] = {{ SYSVAR_EPOCH_SCHED_ID }}, + [ FD_SYSVAR_last_restart_slot_IDX ] = {{ SYSVAR_LAST_RESTART_ID }}, + [ FD_SYSVAR_recent_hashes_IDX ] = {{ SYSVAR_RECENT_BLKHASH_ID }}, + [ FD_SYSVAR_rent_IDX ] = {{ SYSVAR_RENT_ID }}, + [ FD_SYSVAR_slot_hashes_IDX ] = {{ SYSVAR_SLOT_HASHES_ID }}, + [ FD_SYSVAR_slot_history_IDX ] = {{ SYSVAR_SLOT_HIST_ID }}, + [ FD_SYSVAR_stake_history_IDX ] = {{ SYSVAR_STAKE_HIST_ID }}, +}; + +/* 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_restore. */ + +void +fd_sysvar_account_update( fd_exec_slot_ctx_t * slot_ctx, + fd_pubkey_t const * address, + void const * data, + ulong sz ); + +/* fd_sysvar_obj_restore restores a typed representation of a sysvar + from serialized data. This is called internally whenever sysvar + serialized data is updated directly. DO NOT USE DIRECTLY. */ + +int +fd_sysvar_obj_restore( fd_sysvar_cache_t * cache, + fd_sysvar_desc_t * desc, + fd_sysvar_pos_t const * pos, + int log_fails ); + +#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..72a97110ea 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,19 @@ 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_bank_t * bank = slot_ctx->bank; + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( 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 +149,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 ); @@ -245,17 +195,18 @@ fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, uchar * data = fd_solana_account_data_join( &n->elem.value ); ulong data_len = n->elem.value.data_len; - fd_vote_state_versioned_t * vsv = fd_bincode_decode_spad( - vote_state_versioned, runtime_spad, - data, - data_len, - &err ); - if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) { - FD_LOG_WARNING(( "Vote state versioned decode failed" )); - continue; - } - - switch( vsv->discriminant ) { + FD_SPAD_FRAME_BEGIN( spad ) { + fd_vote_state_versioned_t * vsv = fd_bincode_decode_spad( + vote_state_versioned, spad, + data, + data_len, + &err ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) { + FD_LOG_WARNING(( "Vote state versioned decode failed" )); + continue; + } + + switch( vsv->discriminant ) { case fd_vote_state_versioned_enum_v0_23_5: vote_timestamp = (ulong)vsv->inner.v0_23_5.last_timestamp.timestamp; vote_slot = vsv->inner.v0_23_5.last_timestamp.slot; @@ -270,16 +221,17 @@ fd_calculate_stake_weighted_timestamp( fd_bank_t * bank, break; default: __builtin_unreachable(); + } } + FD_SPAD_FRAME_END; } else { vote_timestamp = (ulong)vote_acc_node->elem.timestamp; 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 +277,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 +346,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 ); - - fd_epoch_schedule_t const * epoch_schedule = fd_bank_epoch_schedule_query( bank ); + clock.slot = fd_bank_slot_get( 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..f067905655 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_clock.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_clock.h @@ -3,60 +3,47 @@ /* 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 "fd_sysvar_base.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_SYSVAR_CLOCK_STAKE_WEIGHTS_MAX specifies the max number of stake + weights processed in a clock update. */ + +#define FD_SYSVAR_CLOCK_STAKE_WEIGHTS_MAX (10240UL) + FD_PROTOTYPES_BEGIN /* The clock sysvar provides an approximate measure of network time. */ -/* Initialize the clock sysvar account. */ +/* fd_sysvar_clock_init initializes the sysvar account to genesis state. */ void -fd_sysvar_clock_init( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn ); +fd_sysvar_clock_init( fd_exec_slot_ctx_t * slot_ctx ); -/* Update the clock sysvar account. This should be called at the start - of every slot, before execution commences. */ +/* 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). */ -int -fd_sysvar_clock_update( fd_bank_t * bank, - fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * runtime_spad ); +void +fd_calculate_stake_weighted_timestamp( fd_exec_slot_ctx_t * slot_ctx, + long * result_timestamp, + fd_spad_t * spad ); -/* Writes the current value of the clock sysvar to funk. */ +/* 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_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_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 ) { - ulong seconds = (2UL * 24UL * 60UL * 60UL); - ulong ticks = seconds * FD_SYSVAR_CLOCK_DEFAULT_HASHES_PER_TICK; - return ticks / ticks_per_slot; -} +fd_sysvar_clock_update( fd_exec_slot_ctx_t * slot_ctx, + fd_spad_t * spad ); FD_PROTOTYPES_END diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c index ab9c3fed65..40d94db95b 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.c @@ -1,50 +1,6 @@ #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_sysvar_epoch_rewards_t * out ) { - 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_static( - sysvar_epoch_rewards, out, - 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 @@ -53,8 +9,8 @@ void fd_sysvar_epoch_rewards_distribute( fd_exec_slot_ctx_t * slot_ctx, ulong distributed ) { fd_sysvar_epoch_rewards_t epoch_rewards[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, epoch_rewards ) ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); + 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 ) ) { @@ -67,14 +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_sysvar_epoch_rewards_t epoch_rewards[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( slot_ctx->funk, slot_ctx->funk_txn, epoch_rewards ) ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch rewards" )); + 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 ) ) { @@ -83,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 @@ -111,5 +67,5 @@ fd_sysvar_epoch_rewards_init( fd_exec_slot_ctx_t * slot_ctx, FD_LOG_ERR(( "total rewards overflow" )); } - 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 b65fc5d216..9f571de643 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_rewards.h @@ -1,21 +1,11 @@ #ifndef HEADER_fd_src_flamenco_runtime_sysvar_epoch_rewards_h #define HEADER_fd_src_flamenco_runtime_sysvar_epoch_rewards_h -#include "../../fd_flamenco_base.h" +#include "fd_sysvar_base.h" #include "../../types/fd_types.h" -#include "../context/fd_exec_slot_ctx.h" FD_PROTOTYPES_BEGIN -/* 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. */ - -fd_sysvar_epoch_rewards_t * -fd_sysvar_epoch_rewards_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_sysvar_epoch_rewards_t * out ); - /* Update EpochRewards sysvar with distributed rewards https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/sdk/program/src/epoch_rewards.rs#L44 */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c index f7730a669e..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,56 +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 ); - /* 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_epoch_schedule_t * out ) { - - 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_static( - epoch_schedule, out, - 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 b389c1b00d..35b536f470 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.h @@ -30,7 +30,7 @@ The epoch schedule sysvar contains epoch scheduling constants used to make various epoch-related calculations. */ -#include "../../fd_flamenco_base.h" +#include "fd_sysvar_base.h" #include "../context/fd_exec_slot_ctx.h" /* FD_EPOCH_LEN_MIN is a protocol constant specifying the smallest @@ -54,28 +54,6 @@ FD_PROTOTYPES_BEGIN -/* fd_sysvar_epoch_schedule_init initializes the epoch schedule sysvar - account. FIXME document what this actually does. */ - -void -fd_sysvar_epoch_schedule_init( fd_exec_slot_ctx_t * slot_ctx ); - -/* 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_epoch_schedule_t * out ); - -/* 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_epoch_schedule_derive derives an epoch schedule config from the given parameters. New epoch schedule configurations should only be created using this function. Returns schedule on success. 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 cde56d40d3..16d4eb935f 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 ) { @@ -11,82 +9,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..a8d2154d87 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_last_restart_slot.h @@ -1,9 +1,9 @@ #ifndef HEADER_fd_src_flamenco_runtime_fd_sysvar_last_restart_slot_h #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" +#include "fd_sysvar_base.h" + +typedef struct fd_hard_forks_global fd_hard_forks_global_t; FD_PROTOTYPES_BEGIN @@ -14,20 +14,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 f3da4cb95f..4563d62831 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c @@ -1,8 +1,7 @@ #include "fd_sysvar_recent_hashes.h" -#include "../fd_acc_mgr.h" -#include "fd_sysvar.h" -#include "../fd_system_ids.h" #include "../context/fd_exec_slot_ctx.h" +#include "../fd_system_ids.h" +#include "fd_sysvar_cache.h" /* Skips fd_types encoding preflight checks and directly serializes the blockhash queue into a buffer representing account data for the @@ -36,22 +35,15 @@ encode_rbh_from_blockhash_queue( fd_blockhashes_t const * bhq, } void -fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ) { - - FD_SPAD_FRAME_BEGIN( runtime_spad ) { - - if( fd_bank_slot_get( slot_ctx->bank ) != 0 ) { - return; - } +fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx ) { - ulong sz = FD_SYSVAR_RECENT_HASHES_BINCODE_SZ; - uchar * enc = fd_spad_alloc( runtime_spad, FD_SPAD_ALIGN, sz ); - fd_memset( enc, 0, sz ); - encode_rbh_from_blockhash_queue( fd_bank_block_hash_queue_query( slot_ctx->bank ), 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 ) ); + 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 ); - } FD_SPAD_FRAME_END; } // https://github.com/anza-xyz/agave/blob/e8750ba574d9ac7b72e944bc1227dc7372e3a490/accounts-db/src/blockhash_queue.rs#L113 @@ -65,75 +57,21 @@ register_blockhash( fd_exec_slot_ctx_t * slot_ctx, }; } -/* 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_SYSVAR_RECENT_HASHES_BINCODE_SZ; - 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( fd_bank_block_hash_queue_query( slot_ctx->bank ), 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_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; + /* Update sysvar account with latest 150 hashes */ + fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( sysvar_cache ) ) ) { + fd_sysvar_recent_hashes_init( slot_ctx ); } - - 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" )); - } - - /* 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; - } - - return fd_recent_block_hashes_decode( 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( fd_bank_block_hash_queue_query( slot_ctx->bank ), 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 5acdb8ed65..79b0e3583f 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h @@ -1,47 +1,34 @@ -#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 -#include "../../types/fd_types.h" -#include "../../fd_flamenco_base.h" -#include "../../../funk/fd_funk.h" +/* fd_sysvar_recent_hashes.h manages the "recent block hashes" sysvar + account (address SysvarRecentB1ockHashes11111111111111111111). */ + +#include "fd_sysvar_base.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_SYSVAR_RECENT_HASHES_BINCODE_SZ is the serialized size of the - recent block hashes sysvar account. (static/hardcoded) - - Agave v2.2.1: https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/sysvar/src/recent_blockhashes.rs#L157 */ - -#define FD_SYSVAR_RECENT_HASHES_BINCODE_SZ (6008UL) - FD_PROTOTYPES_BEGIN -/* The recent hashes sysvar */ +/* 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). */ -/* Initialize the recent hashes sysvar account. */ void -fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx, - fd_spad_t * runtime_spad ); - -/* 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 ); +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). */ -/* 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_recent_block_hashes_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_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..ba533fe9dc 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_rent.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_rent.h @@ -1,23 +1,10 @@ #ifndef HEADER_fd_src_flamenco_runtime_fd_sysvar_rent_h #define HEADER_fd_src_flamenco_runtime_fd_sysvar_rent_h -#include "../../fd_flamenco_base.h" +#include "fd_sysvar_base.h" #include "../../types/fd_types.h" -#include "../../../funk/fd_funk.h" -FD_PROTOTYPES_BEGIN - -/* fd_sysvar_rent_init copies the cached rent sysvar stored from - fd_exec_slot_ctx_t to the corresponding account in the database. - Note that it does NOT initialize global->bank.rent */ - -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_PROTOTYPES_BEGIN /* fd_rent_exempt_minimum_balance returns the minimum balance needed for an account with the given data_len to be rent exempt. rent @@ -27,15 +14,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..5d84b983ea 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_slot_hashes_is_valid( sysvar_cache ) ) ) { + 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( slot_ctx ); + 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( slot_ctx, 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..5b6bb122df 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_hashes.h @@ -1,62 +1,34 @@ -#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 -#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.h manages the "slot hashes" sysvar account + (address SysvarS1otHashes111111111111111111111111111). + + This sysvar contains bank hashes of previous slots. */ + +#include "fd_sysvar_base.h" /* 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 */ + https://docs.rs/solana-slot-hashes/2.2.1/src/solana_slot_hashes/lib.rs.html#21 */ -#define FD_SYSVAR_SLOT_HASHES_CAP (512UL) -#define FD_SYSVAR_SLOT_HASHES_ALIGN (FD_SLOT_HASHES_GLOBAL_ALIGN) +#define FD_SYSVAR_SLOT_HASHES_CAP (512UL) FD_PROTOTYPES_BEGIN +/* fd_sysvar_slot_hashes_init creates a "slot hashes" sysvar account + (overwrites an existing one). */ -ulong -fd_sysvar_slot_hashes_footprint( ulong slot_hashes_cap ); - -void * -fd_sysvar_slot_hashes_new( void * mem, - ulong slot_hashes_cap ); - -fd_slot_hashes_global_t * -fd_sysvar_slot_hashes_join( void * shmem, - fd_slot_hash_t ** slot_hash ); - -void * -fd_sysvar_slot_hashes_leave( fd_slot_hashes_global_t * slot_hashes_global, - fd_slot_hash_t * slot_hash ); - -void * -fd_sysvar_slot_hashes_delete( void * mem ); - -/* 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 f15b3db35c..d678b37023 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.c @@ -1,212 +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_SPAD_FRAME_BEGIN( runtime_spad ) { + /* 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_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#L64-L69 */ + fd_memset( bitvec_blocks( history ), 0, sizeof(ulong) * FD_SYSVAR_SLOT_HISTORY_BLOCK_CNT ); - 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 )); - - 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; ibank ) ); - history->next_slot = fd_bank_slot_get( slot_ctx->bank ) + 1; - - ulong sz = fd_ulong_max( rec->vt->get_data_len( rec ), slot_history_min_account_size ); - err = fd_txn_account_init_from_funk_mutable( rec, key, slot_ctx->funk, slot_ctx->funk_txn, 0, sz ); - if (err) - FD_LOG_CRIT(( "fd_txn_account_init_from_funk_mutable(slot_history) failed: %d", err )); + /* https://github.com/anza-xyz/solana-sdk/blob/slot-history%40v2.2.1/slot-history/src/lib.rs#L75-L76 */ + bitvec_insert( history, slot % FD_SYSVAR_SLOT_HISTORY_MAX_ENTRIES ); + history->next_slot = slot + 1UL; - fd_bincode_encode_ctx_t e_ctx = { - .data = rec->vt->get_data_mut( rec ), - .dataend = rec->vt->get_data_mut( rec )+sz, - }; +} - if( FD_UNLIKELY( fd_slot_history_encode_global( history, &e_ctx ) ) ) { - FD_LOG_ERR(( "fd_slot_history_encode_global failed" )); - } +/* 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 */ - fd_rent_t const * rent = fd_bank_rent_query( slot_ctx->bank ); - rec->vt->set_lamports( rec, fd_rent_exempt_minimum_balance( rent, sz ) ); +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; - rec->vt->set_data_len( rec, sz ); - rec->vt->set_owner( rec, &fd_sysvar_owner_id ); + FD_SPAD_FRAME_BEGIN( runtime_spad ) { - fd_txn_account_mutable_fini( rec, slot_ctx->funk, slot_ctx->funk_txn ); + 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) ); - return 0; + 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 ); } 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 */ +/* See solana_runtime::bank::Bank::update_slot_history + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2276 */ - fd_pubkey_t const * key = &fd_sysvar_slot_history_id; - - 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 )); - } - - /* 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; +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_slot_history_is_valid( sysvar_cache ) ) ) { + fd_sysvar_slot_history_init( slot_ctx, runtime_spad ); } - fd_bincode_decode_ctx_t ctx = { - .data = rec->vt->get_data( rec ), - .dataend = rec->vt->get_data( rec ) + rec->vt->get_data_len( rec ) - }; + /* 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 */ - ulong total_sz = 0UL; - err = fd_slot_history_decode_footprint( &ctx, &total_sz ); - if( err ) { - FD_LOG_ERR(( "fd_slot_history_decode_footprint failed" )); - } + fd_slot_history_global_t * history = fd_sysvar_slot_history_join( slot_ctx ); + if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "Slot history sysvar is invalid, cannot update" )); - uchar * mem = fd_spad_alloc( spad, fd_slot_history_align(), total_sz ); - if( !mem ) { - FD_LOG_ERR(( "Unable to allocate memory for slot history" )); - } + /* Advance to current slot, set this slot's bit. + https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2282 */ - 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( slot_ctx, 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..fdc2f5ac70 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_slot_history.h @@ -1,38 +1,70 @@ -#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 -#include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" -#include "../context/fd_exec_slot_ctx.h" +/* fd_sysvar_slot_history.h manages the "slot history" sysvar account + (address SysvarS1otHistory11111111111111111111111111). -#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) + 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). */ -/* The slot history sysvar contains a bit-vector indicating which slots have been processed in the current epoch. */ +#include "fd_sysvar_base.h" + +/* 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 + +/* Slot Freeze ********************************************************/ + +/* 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 ); -/* Update the slot history sysvar account. This should be called at the end of every slot, after execution has concluded. */ -int +/* 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 */ + +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_slot_history_global_t * -fd_sysvar_slot_history_read( fd_funk_t * funk, - fd_funk_txn_t * funk_txn, - fd_spad_t * spad ); +/* 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. + + 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 ec25dff8a1..d406b915ef 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c @@ -1,66 +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. */ - -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")); +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 ); - 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 ) ); } -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; - } +/* https://github.com/anza-xyz/agave/blob/v2.3.2/runtime/src/bank.rs#L2365 */ - /* 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; - } +void +fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, + fd_epoch_stake_history_entry_pair_t const * entry ) { - return fd_bincode_decode_spad( - stake_history, spad, - stake_rec->vt->get_data( stake_rec ), - stake_rec->vt->get_data_len( stake_rec ), - &err ); -} + 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 ); -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 ); -} + 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 ); -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_SPAD_FRAME_BEGIN( runtime_spad ) { + if( FD_LIKELY( prev_epoch==cur_epoch ) ) return; - // 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 ); + if( FD_UNLIKELY( !fd_sysvar_stake_history_is_valid( sysvar_cache ) ) ) { + fd_sysvar_stake_history_init( slot_ctx ); + } + + fd_stake_history_t * stake_history = fd_sysvar_stake_history_join( slot_ctx ); + 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; @@ -73,14 +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; - - write_stake_history( slot_ctx, stake_history ); + stake_history->fd_stake_history[ idx ] = *entry; - } FD_SPAD_FRAME_END; + fd_sysvar_stake_history_leave( slot_ctx, 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..f25f6942e5 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.h @@ -1,40 +1,43 @@ -#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 -#include "../../fd_flamenco_base.h" -#include "../../types/fd_types.h" -#include "../../../funk/fd_funk.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_sysvar_base.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_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..f62da128e3 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar.c @@ -0,0 +1,33 @@ +#include "test_sysvar_cache.c" +#include "test_sysvar_clock.c" +#include "test_sysvar_epoch_rewards.c" +#include "test_sysvar_epoch_schedule.c" +#include "test_sysvar_last_restart_slot.c" +#include "test_sysvar_recent_hashes.c" +#include "test_sysvar_rent.c" +#include "test_sysvar_slot_hashes.c" +#include "test_sysvar_slot_history.c" +#include "test_sysvar_stake_history.c" +#include "../../../util/fd_util.h" + +int +main( int argc, + char ** argv ) { + fd_boot( &argc, &argv ); + + test_sysvar_cache(); + + test_sysvar_clock(); + test_sysvar_epoch_rewards(); + test_sysvar_epoch_schedule(); + test_sysvar_last_restart_slot(); + test_sysvar_recent_hashes(); + test_sysvar_rent(); + test_sysvar_slot_hashes(); + test_sysvar_slot_history(); + test_sysvar_stake_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..e325e492bc --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_cache.c @@ -0,0 +1,45 @@ +#include "fd_sysvar_cache_private.h" +#include "../fd_system_ids.h" + +static void +test_sysvar_map( void ) { + sysvar_tbl_t const * s; + + s = sysvar_map_query( &fd_sysvar_clock_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_clock_IDX ); + + s = sysvar_map_query( &fd_sysvar_epoch_rewards_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_epoch_rewards_IDX ); + + s = sysvar_map_query( &fd_sysvar_epoch_schedule_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_epoch_schedule_IDX ); + + s = sysvar_map_query( &fd_sysvar_last_restart_slot_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_last_restart_slot_IDX ); + + s = sysvar_map_query( &fd_sysvar_recent_block_hashes_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_recent_hashes_IDX ); + + s = sysvar_map_query( &fd_sysvar_rent_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_rent_IDX ); + + s = sysvar_map_query( &fd_sysvar_slot_hashes_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_slot_hashes_IDX ); + + s = sysvar_map_query( &fd_sysvar_slot_history_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_slot_history_IDX ); + + s = sysvar_map_query( &fd_sysvar_stake_history_id, NULL ); + FD_TEST( s && s->desc_idx == FD_SYSVAR_stake_history_IDX ); + + for( ulong j=0UL; j<256; j++ ) { + fd_pubkey_t pk; + for( ulong j=0UL; j<32UL; j++ ) pk.uc[j] = (uchar)j; + FD_TEST( !sysvar_map_query( &pk, NULL ) ); + } +} + +static void +test_sysvar_cache( void ) { + test_sysvar_map(); +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_clock.c b/src/flamenco/runtime/sysvar/test_sysvar_clock.c new file mode 100644 index 0000000000..33f9db1188 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_clock.c @@ -0,0 +1,26 @@ +#include "fd_sysvar_clock.h" +#include "../../types/fd_types.h" + +static void +test_sysvar_clock_bounds( void ) { + /* Real sysvar account observed on-chain */ + static uchar const data[] = { + 0xef, 0x04, 0x28, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x95, 0x7d, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x35, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x3a, 0x7f, 0x68, 0x00, 0x00, 0x00, 0x00 + }; + FD_TEST( sizeof(data)==FD_SYSVAR_CLOCK_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+sizeof(data) }; + ulong obj_sz = 0UL; + FD_TEST( fd_sol_sysvar_clock_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_CLOCK_FOOTPRINT ); + FD_TEST( fd_sol_sysvar_clock_align()==FD_SYSVAR_CLOCK_ALIGN ); +} + +static void +test_sysvar_clock( void ) { + test_sysvar_clock_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_epoch_rewards.c b/src/flamenco/runtime/sysvar/test_sysvar_epoch_rewards.c new file mode 100644 index 0000000000..8a72050dfd --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_epoch_rewards.c @@ -0,0 +1,32 @@ +#include "fd_sysvar_epoch_rewards.h" +#include "../../types/fd_types.h" + +static void +test_sysvar_epoch_rewards_bounds( void ) { + /* Real sysvar account observed on-chain */ + static uchar const data[] = { + 0x24, 0x1e, 0xd7, 0x13, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0xc7, 0x32, 0x75, 0xb1, 0x43, 0xba, 0x37, + 0xac, 0x29, 0xf2, 0x25, 0x1a, 0xae, 0x87, 0x2f, + 0x2d, 0x9d, 0x38, 0x62, 0x94, 0x8d, 0xdc, 0xd5, + 0x33, 0x18, 0xe1, 0x43, 0xc2, 0x25, 0x7f, 0x4c, + 0xc6, 0x38, 0xa8, 0x7c, 0x28, 0xb3, 0xcb, 0x95, + 0x5b, 0x48, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0x3a, 0xbf, 0x62, 0xae, 0x84, 0x00, 0x00, + 0xc7, 0xb8, 0xad, 0x62, 0xae, 0x84, 0x00, 0x00, + 0x00 + }; + FD_TEST( sizeof(data)==FD_SYSVAR_EPOCH_REWARDS_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+sizeof(data) }; + ulong obj_sz = 0UL; + FD_TEST( fd_sysvar_epoch_rewards_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_EPOCH_REWARDS_FOOTPRINT ); + FD_TEST( fd_sysvar_epoch_rewards_align()==FD_SYSVAR_EPOCH_REWARDS_ALIGN ); +} + +static void +test_sysvar_epoch_rewards( void ) { + test_sysvar_epoch_rewards_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c b/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c index 6514e261ff..d4d9657b5e 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c @@ -10,6 +10,24 @@ FD_STATIC_ASSERT( offsetof( fd_epoch_schedule_t, first_normal_epoch )== FD_STATIC_ASSERT( offsetof( fd_epoch_schedule_t, first_normal_slot )==0x20UL, layout ); FD_STATIC_ASSERT( sizeof ( fd_epoch_schedule_t )==0x28UL, layout ); +static void +test_sysvar_epoch_schedule_bounds( void ) { + /* Real sysvar account observed on-chain */ + static uchar const data[] = { + 0x80, 0x97, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x97, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 + }; + FD_TEST( sizeof(data)==FD_SYSVAR_EPOCH_SCHEDULE_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+sizeof(data) }; + ulong obj_sz = 0UL; + FD_TEST( fd_epoch_schedule_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_EPOCH_SCHEDULE_FOOTPRINT ); + FD_TEST( fd_epoch_schedule_align()==FD_SYSVAR_EPOCH_SCHEDULE_ALIGN ); +} + static fd_epoch_schedule_t const fd_epoch_schedule_test_vectors[] = { { .slots_per_epoch= 32, .first_normal_epoch=0, .first_normal_slot= 0 }, @@ -94,20 +112,12 @@ 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 ) { + test_sysvar_epoch_schedule_bounds(); for( fd_epoch_schedule_t const * vec = fd_epoch_schedule_test_vectors; vec->slots_per_epoch; vec++ ) { - test_epoch_schedule_derive( vec ); test_epoch_schedule ( vec ); - } - - FD_LOG_NOTICE(( "pass" )); - fd_halt(); - return 0; } diff --git a/src/flamenco/runtime/sysvar/test_sysvar_last_restart_slot.c b/src/flamenco/runtime/sysvar/test_sysvar_last_restart_slot.c new file mode 100644 index 0000000000..67f8aab515 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_last_restart_slot.c @@ -0,0 +1,22 @@ +#include "fd_sysvar_last_restart_slot.h" +#include "../../types/fd_types.h" + +static void +test_sysvar_last_restart_slot_bounds( void ) { + /* Real sysvar account observed on-chain */ + static uchar const data[] = { + 0x28, 0xbe, 0xb0, 0x0e, 0x00, 0x00, 0x00, 0x00 + }; + FD_TEST( sizeof(data)==FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+sizeof(data) }; + ulong obj_sz = 0UL; + FD_TEST( fd_sol_sysvar_last_restart_slot_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT ); + FD_TEST( fd_sol_sysvar_last_restart_slot_align()==FD_SYSVAR_LAST_RESTART_SLOT_ALIGN ); +} + +static void +test_sysvar_last_restart_slot( void ) { + test_sysvar_last_restart_slot_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.bin b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..b920fd01f497c6c5637383ae14d5120bc33dc041 GIT binary patch literal 6008 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 Rpk+POb)(w*1m#-5{ReZ_z48D6 literal 0 HcmV?d00001 diff --git a/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c new file mode 100644 index 0000000000..90afa012c9 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c @@ -0,0 +1,23 @@ +#include "fd_sysvar_recent_hashes.h" +#include "../../types/fd_types.h" + +FD_IMPORT_BINARY( example_recent_hashes, "src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.bin" ); + +static void +test_sysvar_recent_hashes_bounds( void ) { + FD_TEST( example_recent_hashes_sz==FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { + .data = example_recent_hashes, + .dataend = example_recent_hashes + example_recent_hashes_sz + }; + ulong obj_sz = 0UL; + FD_TEST( fd_recent_block_hashes_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_RECENT_HASHES_FOOTPRINT ); + FD_TEST( fd_recent_block_hashes_align()==FD_SYSVAR_RECENT_HASHES_ALIGN ); +} + +static void +test_sysvar_recent_hashes( void ) { + test_sysvar_recent_hashes_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_rent.c b/src/flamenco/runtime/sysvar/test_sysvar_rent.c index 6fb0807e0a..3153a7ca83 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_rent.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_rent.c @@ -1,5 +1,21 @@ #include "fd_sysvar_rent.h" +static void +test_sysvar_rent_bounds( void ) { + /* Real sysvar account observed on-chain */ + static uchar const data[] = { + 0x98, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, + 0x64 + }; + FD_TEST( sizeof(data)==FD_SYSVAR_RENT_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { .data=data, .dataend=data+sizeof(data) }; + ulong obj_sz = 0UL; + FD_TEST( fd_rent_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_RENT_FOOTPRINT ); + FD_TEST( fd_rent_align()==FD_SYSVAR_RENT_ALIGN ); +} + struct fd_rent_exempt_fixture { /* Inputs */ ulong data_len; @@ -40,14 +56,10 @@ 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 ); - - fd_rent_exempt_fixture_t const * iter; - for( iter = test_rent_exempt_vector; +void +test_sysvar_rent( void ) { + test_sysvar_rent_bounds(); + for( fd_rent_exempt_fixture_t const * iter = test_rent_exempt_vector; iter < test_rent_exempt_vector_end; iter++ ) { fd_rent_t rent = { @@ -57,8 +69,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_hashes.bin b/src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..b04e721967d18be4f1756b0ca613e1e95a695e3c GIT binary patch literal 20488 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 literal 0 HcmV?d00001 diff --git a/src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.c b/src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.c new file mode 100644 index 0000000000..9a5ba79337 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.c @@ -0,0 +1,23 @@ +#include "fd_sysvar_slot_hashes.h" +#include "../../types/fd_types.h" + +FD_IMPORT_BINARY( example_slot_hashes, "src/flamenco/runtime/sysvar/test_sysvar_slot_hashes.bin" ); + +static void +test_sysvar_slot_hashes_bounds( void ) { + FD_TEST( example_slot_hashes_sz==FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { + .data = example_slot_hashes, + .dataend = example_slot_hashes + example_slot_hashes_sz + }; + ulong obj_sz = 0UL; + FD_TEST( fd_slot_hashes_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_SLOT_HASHES_FOOTPRINT ); + FD_TEST( fd_slot_hashes_align()==FD_SYSVAR_SLOT_HASHES_ALIGN ); +} + +static void +test_sysvar_slot_hashes( void ) { + test_sysvar_slot_hashes_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_slot_history.bin b/src/flamenco/runtime/sysvar/test_sysvar_slot_history.bin new file mode 100644 index 0000000000000000000000000000000000000000..cf2c9cb4b7c0e355129d1de062f7f7b458941082 GIT binary patch literal 131097 zcmeI)OIqtT6ae6K1$5Fe9d;M(&R9Yhbr+B|bO#ySS^GgDJYo{tQDVLIGa=Zr&e4Bl z*$$9jc7N@TUoYoh59b^FT(iI-U2^+PU7JUn_%a==N|~T9!*ocWa51{{Yio;Yw^gqS zvTbt8G?{dSV(%jKk*%GX1^EDwf{6#+69zRZI0&H$5FpU2fIn3%Q`t@bRaGWs zQ3((rK!5-N0t5)867X1(N>;xF1`!zGz2yOhSbDO$6qT+({`gL-{N|Y>J`M6AC#G`d zi6tBX0@VtHt%q*;zvQ2+`cKr?M+KAjDTobatZvjhu-}N;*0t5&UAkd(|Apcv`U}dCC zAeKPDLr6fAd$aK-z`b&gBS3%v0RjZ#3M9PYiJPe22!sll)S*(^6%%+Y7Fl2d1WF0` zbca&%;u0W0fB*pk1PBlyKww3{JBceeX?7t`(6=UJ_=#F_G32+MY?^2%&s7uYGZZ8=- z>OdAcn-*Z9Ns`S0aeJpv;u@jTfYL;Wq6-4o1&(V#r3=AbY2`e*o|k>!bN_p}fj!X$ zR_Dw5LwC+u6MfuOb-1r8n`V<)pRUagOX36w)Ffb`si_)0=HlL}$Eq3=0RjXF5FkK+ z009C72oNAZfB=DD0dGPFQ)x(m009C72oUH0--1f{^ z=U(62_Q=Q1eyqxla|>HfUGqM!)HCi;*A*2Qwesc1?S8O)4P-!IBH(f`!T5T4sWRPS z8T*1N@nTwv67j`sRlv+?wQ~9Mo-Fc{mmzuF*t}4eAz^d1Ng$R!b&E-QV-eB`tetdg z`_g3;-t(3GR!_|<$A%}-N6S^KK89!%%?g;E&6aL+;%dK{PzMAE5SSOpawlAH75_fI z??0VHmbQPj*f4^RzR!A?L_FK`6|$&!`+m89p?s*@|Y1dm7S6ZJMeq=RC?}p4i zlwOZG9uydG8r*9F1PBlyK!5;&Is_&+fs>bY;EB0|B6c-|6j%F*eI6qA z)m7c9AB?50`VvWy009D-1;+UtfW)xwjS>T2?_LS68_l%%F|*C4bOLV1)7k2oK)V8& zR)%V?lbOcf?gWu}905-~aUAtRfB*pk1PF{Ou&-m_r>BQ%A8_h`l7$Ik4iH!qI4!1Y zt?bJ#u<5M}Rn1;60SOQwK%f$VO&8Eg#*izGN}lX<4Obij1cC)TO$1Xl+wkCW*=+43 zPJjRb0tB`R_HTjW zK~A?e^3Z#$SjX*6hK`GCXaoolXi}iWAIX)7*<^7fO`ubO*46+|$(>F_!y-U{0D&ko=IEm1q2=Hcg8%^n;|V-I=Nj`Zm#ACX=E`532m&5F zA|Q6!g_FM1!WtHV>ILRkpQY>7zWVV~_EI-oAeR{>N``-~R`!X`T)M literal 0 HcmV?d00001 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..0edaa3b0ee --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_slot_history.c @@ -0,0 +1,23 @@ +#include "fd_sysvar_slot_history.h" +#include "../../types/fd_types.h" + +FD_IMPORT_BINARY( example_slot_history, "src/flamenco/runtime/sysvar/test_sysvar_slot_history.bin" ); + +static void +test_sysvar_slot_history_bounds( void ) { + FD_TEST( example_slot_history_sz==FD_SYSVAR_SLOT_HISTORY_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { + .data = example_slot_history, + .dataend = example_slot_history + example_slot_history_sz + }; + ulong obj_sz = 0UL; + FD_TEST( fd_slot_history_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_SLOT_HISTORY_FOOTPRINT ); + FD_TEST( fd_slot_history_align()==FD_SYSVAR_SLOT_HISTORY_ALIGN ); +} + +static void +test_sysvar_slot_history( void ) { + test_sysvar_slot_history_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/sysvar/test_sysvar_stake_history.bin b/src/flamenco/runtime/sysvar/test_sysvar_stake_history.bin new file mode 100644 index 0000000000000000000000000000000000000000..ec16cf59c1d220c1bd2feebe21b693a3f75b6309 GIT binary patch literal 16392 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 IZjyli2dpXh6951J literal 0 HcmV?d00001 diff --git a/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c b/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c new file mode 100644 index 0000000000..5224bad777 --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c @@ -0,0 +1,23 @@ +#include "fd_sysvar_stake_history.h" +#include "../../types/fd_types.h" + +FD_IMPORT_BINARY( example_stake_history, "src/flamenco/runtime/sysvar/test_sysvar_stake_history.bin" ); + +static void +test_sysvar_stake_history_bounds( void ) { + FD_TEST( example_stake_history_sz==FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ); + fd_bincode_decode_ctx_t ctx = { + .data = example_stake_history, + .dataend = example_stake_history + example_stake_history_sz + }; + ulong obj_sz = 0UL; + FD_TEST( fd_stake_history_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); + FD_TEST( obj_sz==FD_SYSVAR_STAKE_HISTORY_FOOTPRINT ); + FD_TEST( fd_stake_history_align()==FD_SYSVAR_STAKE_HISTORY_ALIGN ); +} + +static void +test_sysvar_stake_history( void ) { + test_sysvar_stake_history_bounds(); + /* FIXME more tests here ... */ +} diff --git a/src/flamenco/runtime/tests/fd_dump_pb.c b/src/flamenco/runtime/tests/fd_dump_pb.c index 724a84c189..8c31a6306b 100644 --- a/src/flamenco/runtime/tests/fd_dump_pb.c +++ b/src/flamenco/runtime/tests/fd_dump_pb.c @@ -834,9 +834,9 @@ 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_BLOCKHASHES_MAX) * sizeof(pb_bytes_array_t *)) ); + spad, + alignof(pb_bytes_array_t *), + PB_BYTES_ARRAY_T_ALLOCSIZE((FD_BLOCKHASHES_MAX) * sizeof(pb_bytes_array_t *)) ); txn_context_msg->blockhash_queue = output_blockhash_queue; fd_blockhashes_t const * block_hash_queue = fd_bank_block_hash_queue_query( txn_ctx->bank ); dump_blockhash_queue( block_hash_queue, spad, output_blockhash_queue, &txn_context_msg->blockhash_queue_count ); diff --git a/src/flamenco/runtime/tests/harness/fd_block_harness.c b/src/flamenco/runtime/tests/harness/fd_block_harness.c index 6dfae1a6bf..b50838d9c7 100644 --- a/src/flamenco/runtime/tests/harness/fd_block_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_block_harness.c @@ -329,6 +329,9 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, &pubkey ); } + /* Restore sysvar cache */ + FD_TEST( fd_sysvar_cache_restore( slot_ctx )==0 ); + /* Refresh vote accounts to calculate stake delegations */ fd_runtime_fuzz_block_refresh_vote_accounts( vote_accounts_pool, vote_accounts_root, @@ -341,15 +344,11 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_stakes_stake_delegations_pool_update( stakes, stake_delegations_pool ); fd_stakes_stake_delegations_root_update( stakes, stake_delegations_root ); - /* Finish init epoch bank sysvars */ - fd_epoch_schedule_t epoch_schedule_[1]; - fd_epoch_schedule_t * epoch_schedule = fd_sysvar_epoch_schedule_read( funk, funk_txn, epoch_schedule_ ); - fd_bank_epoch_schedule_set( slot_ctx->bank, *epoch_schedule ); - - fd_rent_t const * rent = fd_sysvar_rent_read( funk, funk_txn, runner->spad ); - fd_bank_rent_set( slot_ctx->bank, *rent ); + 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 ); - 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 ); @@ -406,9 +405,9 @@ 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_t const * rbh = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad ); - if( rbh && !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 ); + fd_block_block_hash_entry_t const * rbh = fd_sysvar_recent_hashes_join_const( sysvar_cache ); + if( FD_UNLIKELY( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh ) ) ) { + fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh ); 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 ); @@ -420,7 +419,7 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_hash_t hash; memcpy( &hash, test_ctx->blockhash_queue[i]->bytes, sizeof(fd_hash_t) ); fd_bank_poh_set( slot_ctx->bank, hash ); - fd_sysvar_recent_hashes_update( slot_ctx, runner->spad ); /* appends an entry */ + fd_sysvar_recent_hashes_update( slot_ctx ); /* appends an entry */ } // Set the current poh from the input (we skip POH verification in this fuzzing target) @@ -435,7 +434,7 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_funk_txn_end_write( funk ); /* Calculate epoch account hash values. This sets epoch_bank.eah_{start_slot, stop_slot, interval} */ - fd_calculate_epoch_accounts_hash_values( slot_ctx ); + fd_calculate_epoch_accounts_hash_values( slot_ctx->bank ); /* Prepare raw transaction pointers and block / microblock infos */ ulong txn_cnt = test_ctx->txns_count; diff --git a/src/flamenco/runtime/tests/harness/fd_instr_harness.c b/src/flamenco/runtime/tests/harness/fd_instr_harness.c index 70778fb0e6..3c5c9c6ad9 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,8 +39,8 @@ 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->banks = runner->banks; @@ -60,11 +55,6 @@ 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 */ ulong blockhash_seed; FD_TEST( fd_rng_secure( &blockhash_seed, sizeof(ulong) ) ); @@ -206,28 +196,42 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, } } + /* Restore sysvar cache */ + FD_TEST( fd_sysvar_cache_restore( slot_ctx )==0 ); + ctx->sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); + /* 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 ); + + /* Rent */ + // https://github.com/firedancer-io/solfuzz-agave/blob/agave-v2.0/src/lib.rs#L487-L500 + if( !fd_sysvar_rent_is_valid( sysvar_cache ) ) { + fd_rent_t sysvar_rent = { + .lamports_per_uint8_year = 3480UL, + .exemption_threshold = 2.0, + .burn_percent = 50 + }; + fd_sysvar_rent_write( slot_ctx, &sysvar_rent ); + } /* 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_clock_is_valid( sysvar_cache ) ) { 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 epoch_schedule[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( funk, funk_txn, epoch_schedule ) ) ) { + if( !fd_sysvar_epoch_schedule_is_valid( sysvar_cache ) ) { fd_epoch_schedule_t sysvar_epoch_schedule = { .slots_per_epoch = 432000UL, .leader_schedule_slot_offset = 432000UL, @@ -238,55 +242,21 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, 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 ) { - fd_rent_t sysvar_rent = { - .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_last_restart_slot_is_valid( sysvar_cache ) ) { 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 ) ); - + fd_sysvar_last_restart_slot_write( slot_ctx, &restart ); } /* 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 (!!!) */ - - if( fd_sysvar_epoch_schedule_read( funk, funk_txn, 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_sol_sysvar_clock_t const clock = fd_sysvar_clock_read_nofail( sysvar_cache ); + slot_ctx->bank->slot_ = clock.slot; } /* Override most recent blockhash if given */ - fd_recent_block_hashes_t const * rbh = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad ); - if( rbh && !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 ); + fd_block_block_hash_entry_t const * rbh = fd_sysvar_recent_hashes_join_const( sysvar_cache ); + if( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh ) ) { + fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( rbh ); if( last ) { fd_blockhashes_t * blockhashes = fd_bank_block_hash_queue_modify( slot_ctx->bank ); fd_blockhashes_pop_new( blockhashes ); diff --git a/src/flamenco/runtime/tests/harness/fd_txn_harness.c b/src/flamenco/runtime/tests/harness/fd_txn_harness.c index 9fdda241da..69bb2b056b 100644 --- a/src/flamenco/runtime/tests/harness/fd_txn_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_txn_harness.c @@ -35,8 +35,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->banks = runner->banks; slot_ctx->bank = runner->bank; @@ -86,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_TEST( fd_sysvar_cache_restore( slot_ctx )==0 ); + 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[1]; - if( fd_sysvar_epoch_schedule_read( funk, funk_txn, 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_memset( sysvar_data, 0, FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); + FD_TEST( sysvar_data && sz_max>=48 ); + FD_STORE( ulong, sysvar_data, 1UL ); + fd_sysvar_cache_data_modify_commit( slot_ctx, &fd_sysvar_slot_hashes_id, FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ); } /* 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 @@ -170,10 +152,9 @@ 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[1]; - if( !fd_sysvar_epoch_rewards_read( funk, funk_txn, epoch_rewards ) ) { + if( !fd_sysvar_epoch_rewards_is_valid( sysvar_cache ) ) { 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, 0UL, 0UL, last_hash); + fd_sysvar_epoch_rewards_init( slot_ctx, 0UL, 2UL, 1UL, 0UL, 0UL, last_hash ); } /* Blockhash queue is given in txn message. We need to populate the following two fields: @@ -186,14 +167,9 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_blockhashes_t * blockhashes = fd_blockhashes_init( fd_bank_block_hash_queue_modify( slot_ctx->bank ), blockhash_seed ); // Save lamports per signature for most recent blockhash, if sysvar cache contains recent block hashes - fd_recent_block_hashes_t const * rbh_sysvar = fd_sysvar_recent_hashes_read( funk, funk_txn, runner->spad ); - fd_recent_block_hashes_t rbh[1]; - if( rbh_sysvar ) { - rbh->hashes = rbh_sysvar->hashes; - } - - if( rbh_sysvar && !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 ); + fd_block_block_hash_entry_t const * rbh = fd_sysvar_recent_hashes_join_const( sysvar_cache ); + if( FD_UNLIKELY( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh ) ) ) { + fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh ); 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 ); @@ -215,7 +191,7 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, } // Recent block hashes cap is 150 (actually 151), while blockhash queue capacity is 300 (actually 301) fd_bank_poh_set( slot_ctx->bank, 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 @@ -225,7 +201,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/runtime/tests/harness/fd_vm_harness.c b/src/flamenco/runtime/tests/harness/fd_vm_harness.c index 231de55378..81d1ab9150 100644 --- a/src/flamenco/runtime/tests/harness/fd_vm_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_vm_harness.c @@ -540,8 +540,9 @@ fd_runtime_fuzz_vm_syscall_run( fd_runtime_fuzz_runner_t * runner, /* There's an instr ctx struct embedded in the txn ctx instr stack. */ fd_exec_instr_ctx_t * instr_ctx = &ctx->txn_ctx->instr_stack[ ctx->txn_ctx->instr_stack_sz - 1 ]; *instr_ctx = (fd_exec_instr_ctx_t) { - .instr = ctx->instr, - .txn_ctx = ctx->txn_ctx, + .instr = ctx->instr, + .txn_ctx = ctx->txn_ctx, + .sysvar_cache = ctx->sysvar_cache }; /* Actually invoke the syscall */ diff --git a/src/flamenco/stakes/fd_stakes.c b/src/flamenco/stakes/fd_stakes.c index bd3fa1dfd4..3dc338a660 100644 --- a/src/flamenco/stakes/fd_stakes.c +++ b/src/flamenco/stakes/fd_stakes.c @@ -2,6 +2,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) @@ -136,7 +137,7 @@ fd_stakes_export( fd_stake_weight_t_mapnode_t const * const in_pool, ulong fd_stake_weights_by_node( fd_vote_accounts_global_t const * accs, - fd_vote_stake_weight_t * weights, + fd_vote_stake_weight_t * const weights, fd_spad_t * runtime_spad ) { /* Estimate size required to store temporary data structures */ @@ -151,7 +152,7 @@ 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 ); + 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" )); @@ -169,9 +170,9 @@ fd_stake_weights_by_node( fd_vote_accounts_global_t const * accs, fd_stake_weight_sort( _weights, weights_cnt ); for( ulong i=0UL; ibank ); + fd_stake_history_t const * stake_history = fd_sysvar_stake_history_join_const( sysvar_cache ); + for( fd_delegation_pair_t_mapnode_t * n = delegation_min; n != NULL; n = fd_delegation_pair_t_map_successor( delegations_pool, n ) ) { @@ -599,12 +602,14 @@ accumulate_stake_cache_delegations( temp_info->stake_infos[delegation_idx].stake = stake_state.inner.stake.stake; temp_info->stake_infos[delegation_idx].account = n->elem.account; - fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, epoch, history, new_rate_activation_epoch ); + fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, epoch, stake_history, new_rate_activation_epoch ); effective += new_entry.effective; activating += new_entry.activating; deactivating += new_entry.deactivating; } + fd_sysvar_stake_history_leave_const( sysvar_cache, stake_history ); + accumulator->effective += effective; accumulator->activating += activating; accumulator->deactivating += deactivating; @@ -617,7 +622,6 @@ accumulate_stake_cache_delegations( void fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx, fd_stakes_global_t const * stakes, - fd_stake_history_t const * history, ulong * new_rate_activation_epoch, fd_stake_history_entry_t * accumulator, fd_epoch_info_t * temp_info, @@ -638,7 +642,6 @@ fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx, accumulate_stake_cache_delegations( batch_delegation_min, slot_ctx, - history, new_rate_activation_epoch, accumulator, stake_delegations_pool, @@ -652,10 +655,8 @@ fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx, fd_account_keys_pair_t_mapnode_t * account_keys_pool = fd_account_keys_account_keys_pool_join( stake_account_keys ); fd_account_keys_pair_t_mapnode_t * account_keys_root = fd_account_keys_account_keys_root_join( stake_account_keys ); - if( !account_keys_pool ) { - fd_bank_stake_account_keys_end_locking_query( slot_ctx->bank ); - return; - } + 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 ); /* The number of account keys aggregated across the epoch is usually small, so there aren't much performance gains from tpooling here. */ for( fd_account_keys_pair_t_mapnode_t * n = fd_account_keys_pair_t_map_minimum( account_keys_pool, account_keys_root ); @@ -684,12 +685,14 @@ fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx, fd_delegation_t * delegation = &stake_state.inner.stake.stake.delegation; temp_info->stake_infos[temp_info->stake_infos_len ].stake = stake_state.inner.stake.stake; temp_info->stake_infos[temp_info->stake_infos_len++].account = n->elem.key; - fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, stakes->epoch, history, new_rate_activation_epoch ); + fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, stakes->epoch, stake_history, new_rate_activation_epoch ); accumulator->effective += new_entry.effective; accumulator->activating += new_entry.activating; accumulator->deactivating += new_entry.deactivating; } + fd_sysvar_stake_history_leave_const( sysvar_cache, stake_history ); + fd_bank_stake_account_keys_end_locking_query( slot_ctx->bank ); } FD_SPAD_FRAME_END; @@ -721,9 +724,6 @@ 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 ); - if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "StakeHistory sysvar is missing from sysvar cache" )); - ulong stake_delegations_size = fd_delegation_pair_t_map_size( stake_delegations_pool, stake_delegations_root ); @@ -744,7 +744,6 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, /* Accumulate stats for stake accounts */ fd_accumulate_stake_infos( slot_ctx, stakes, - history, new_rate_activation_epoch, &accumulator, temp_info, @@ -760,7 +759,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/stakes/fd_stakes.h b/src/flamenco/stakes/fd_stakes.h index 20cb58e255..4b131116fd 100644 --- a/src/flamenco/stakes/fd_stakes.h +++ b/src/flamenco/stakes/fd_stakes.h @@ -75,7 +75,6 @@ fd_populate_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, void fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx, fd_stakes_global_t const * stakes, - fd_stake_history_t const * history, ulong * new_rate_activation_epoch, fd_stake_history_entry_t * accumulator, fd_epoch_info_t * temp_info, diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c b/src/flamenco/vm/syscall/fd_vm_syscall_runtime.c index b3745f52a7..3680f74ade 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,13 +67,12 @@ 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[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( - instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, schedule ) ) ) { - FD_LOG_ERR(( "failed to read sysvar epoch schedule" )); + fd_epoch_schedule_t schedule; + if( FD_UNLIKELY( !fd_sysvar_epoch_schedule_read( instr_ctx->sysvar_cache, &schedule ) ) ) { + 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, schedule, sizeof(fd_epoch_schedule_t) ); + memcpy( var_query.haddr, &schedule, sizeof(fd_epoch_schedule_t) ); *_ret = 0UL; return FD_VM_SUCCESS; @@ -108,15 +86,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; @@ -132,20 +102,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, @@ -154,7 +118,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) ) ); @@ -168,14 +134,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; @@ -190,7 +155,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 */ @@ -234,18 +201,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; @@ -633,22 +598,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 epoch_rewards[1]; - if( FD_UNLIKELY( !fd_sysvar_epoch_rewards_read( - instr_ctx->txn_ctx->funk, instr_ctx->txn_ctx->funk_txn, 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 Date: Fri, 25 Jul 2025 01:35:36 +0000 Subject: [PATCH 3/5] runtime: remove 'recent blockhash' object cache The recent blockhashes object is never read from the sysvar, and Firedancer has always used a custom serializer to convert the bank's blockhash queue to sysvar data. Therefore, we can remove the typed representation of 'recent blockhashes' from the sysvar cache. --- src/flamenco/runtime/sysvar/fd_sysvar_cache.c | 35 ---- src/flamenco/runtime/sysvar/fd_sysvar_cache.h | 31 +-- .../runtime/sysvar/fd_sysvar_cache_db.c | 37 ++-- .../runtime/sysvar/fd_sysvar_cache_private.h | 4 +- .../runtime/sysvar/fd_sysvar_recent_hashes.c | 8 +- .../runtime/sysvar/fd_sysvar_recent_hashes.h | 5 + .../sysvar/test_sysvar_recent_hashes.c | 11 +- .../runtime/tests/harness/fd_block_harness.c | 15 +- .../runtime/tests/harness/fd_harness_common.c | 77 ++++++++ .../runtime/tests/harness/fd_harness_common.h | 8 + .../runtime/tests/harness/fd_instr_harness.c | 19 +- .../runtime/tests/harness/fd_txn_harness.c | 35 ++-- src/flamenco/types/fd_fuzz_types.h | 23 --- src/flamenco/types/fd_types.c | 186 ------------------ src/flamenco/types/fd_types.h | 62 ------ src/flamenco/types/fd_types.json | 16 -- .../types/fd_types_reflect_generated.c | 4 +- 17 files changed, 140 insertions(+), 436 deletions(-) diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache.c b/src/flamenco/runtime/sysvar/fd_sysvar_cache.c index d5083e4484..072633ff7f 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_cache.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache.c @@ -145,41 +145,6 @@ FD_SYSVAR_SIMPLE_ITER( SIMPLE_SYSVAR ) #undef SIMPLE_SYSVAR #undef SIMPLE_SYSVAR_READ -fd_block_block_hash_entry_t * /* deque */ -fd_sysvar_recent_hashes_join( - fd_exec_slot_ctx_t * slot_ctx -) { - ulong const idx = FD_SYSVAR_recent_hashes_IDX; - fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); - if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( cache ) ) ) return NULL; - FD_VOLATILE( cache->desc[ idx ].flags ) = FD_SYSVAR_FLAG_WRITE_LOCK; /* FIXME consider CAS */ - cache->desc[ idx ].data_sz = 0U; - fd_recent_block_hashes_global_t * rbh = (void *)cache->obj_recent_hashes; - fd_block_block_hash_entry_t * deq = deq_fd_block_block_hash_entry_t_join( (uchar *)rbh+rbh->hashes_offset ); - /* If the above is_valid check is passed, then join is guaranteed to succeed */ - if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "recent blockhashes sysvar corruption detected" )); - return deq; -} - -fd_block_block_hash_entry_t const * /* deque */ -fd_sysvar_recent_hashes_join_const( - fd_sysvar_cache_t const * cache -) { - if( FD_UNLIKELY( !fd_sysvar_recent_hashes_is_valid( cache ) ) ) return NULL; - fd_recent_block_hashes_global_t * var = (void *)cache->obj_recent_hashes; - fd_block_block_hash_entry_t * deq = deq_fd_block_block_hash_entry_t_join( (uchar *)var+var->hashes_offset ); - if( FD_UNLIKELY( !deq ) ) FD_LOG_CRIT(( "recent blockhashes sysvar corruption detected" )); - return deq; /* demote to const ptr */ -} - -void -fd_sysvar_recent_hashes_leave_const( - fd_sysvar_cache_t const * sysvar_cache, - fd_block_block_hash_entry_t const * hashes_deque -) { - (void)sysvar_cache; (void)hashes_deque; -} - fd_slot_hash_t * fd_sysvar_slot_hashes_join( fd_exec_slot_ctx_t * slot_ctx diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache.h b/src/flamenco/runtime/sysvar/fd_sysvar_cache.h index 38547fbc4a..151a79f8a8 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_cache.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache.h @@ -52,7 +52,6 @@ struct fd_sysvar_cache { uchar bin_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); uchar obj_last_restart_slot [ FD_SYSVAR_LAST_RESTART_SLOT_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); uchar bin_recent_hashes [ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); - uchar obj_recent_hashes [ FD_SYSVAR_RECENT_HASHES_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); uchar bin_rent [ FD_SYSVAR_RENT_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); uchar obj_rent [ FD_SYSVAR_RENT_FOOTPRINT ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); uchar bin_slot_hashes [ FD_SYSVAR_SLOT_HASHES_BINCODE_SZ ] __attribute__((aligned(FD_SYSVAR_ALIGN_MAX))); @@ -116,6 +115,14 @@ fd_sysvar_cache_delete( void * mem ); int fd_sysvar_cache_restore( fd_exec_slot_ctx_t * slot_ctx ); +/* fd_sysvar_cache_restore_fuzz is a weaker version of the above for use + with solfuzz/protosol conformance tooling. This version works around + bugs in that tooling that create invalid sysvars and suppresses noisy + log warning. */ + +void +fd_sysvar_cache_restore_fuzz( 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 @@ -310,28 +317,6 @@ fd_sysvar_recent_hashes_is_valid( fd_sysvar_cache_t const * sysvar_cache ) { return FD_SYSVAR_IS_VALID( sysvar_cache, recent_hashes ); } -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_exec_slot_ctx_t * slot_ctx, - 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. diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c b/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c index 3915830626..302350aa01 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache_db.c @@ -56,15 +56,15 @@ sysvar_data_fill( fd_sysvar_cache_t * cache, return fd_sysvar_obj_restore( cache, desc, pos, log_fails ); } -int -fd_sysvar_cache_restore( fd_exec_slot_ctx_t * slot_ctx ) { - +static int +fd_sysvar_cache_restore1( fd_exec_slot_ctx_t * slot_ctx, + int log_fails ) { fd_sysvar_cache_t * cache = fd_sysvar_cache_join( fd_sysvar_cache_new( fd_bank_sysvar_cache_modify( slot_ctx->bank ) ) ); int saw_err = 0; for( ulong i=0UL; ibank ); - if( FD_UNLIKELY( FD_VOLATILE_CONST( cache->desc[ idx ].flags )!=FD_SYSVAR_FLAG_WRITE_LOCK ) ) { - FD_LOG_CRIT(( "unmatched sysvar leave" )); - } - fd_recent_block_hashes_global_t const * var = (void *)cache->obj_recent_hashes; - if( FD_UNLIKELY( !hashes || - (ulong)deq_fd_block_block_hash_entry_t_leave( hashes ) != - (ulong)var+var->hashes_offset ) ) { - FD_LOG_CRIT(( "sysvar leave called with invalid pointer" )); - } - sysvar_write_through( slot_ctx, cache, idx, 0UL ); -} - void fd_sysvar_slot_hashes_leave( fd_exec_slot_ctx_t * slot_ctx, diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h b/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h index a7ca4d2c7d..42952cb301 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_cache_private.h @@ -95,9 +95,7 @@ static fd_sysvar_pos_t const fd_sysvar_pos_tbl[ FD_SYSVAR_CACHE_ENTRY_CNT ] = { TYPES_CALLBACKS( sol_sysvar_last_restart_slot, ) }, [FD_SYSVAR_recent_hashes_IDX] = { .name="recent blockhashes", - .data_off=offsetof(fd_sysvar_cache_t, bin_recent_hashes ), .data_max=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ, - .obj_off =offsetof(fd_sysvar_cache_t, obj_recent_hashes ), .obj_max =FD_SYSVAR_RECENT_HASHES_FOOTPRINT, - TYPES_CALLBACKS( recent_block_hashes, _global ) }, + .data_off=offsetof(fd_sysvar_cache_t, bin_recent_hashes ), .data_max=FD_SYSVAR_RECENT_HASHES_BINCODE_SZ }, [FD_SYSVAR_rent_IDX] = { .name="rent", .data_off=offsetof(fd_sysvar_cache_t, bin_rent ), .data_max=FD_SYSVAR_RENT_BINCODE_SZ, diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c index 4563d62831..82fbd5cf33 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.c @@ -7,9 +7,9 @@ blockhash queue into a buffer representing account data for the recent blockhashes sysvar. */ -static void -encode_rbh_from_blockhash_queue( fd_blockhashes_t const * bhq, - uchar out_mem[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] ) { +void +fd_sysvar_recent_hashes_encode( fd_blockhashes_t const * bhq, + uchar out_mem[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] ) { ulong queue_sz = fd_blockhash_deq_cnt( bhq->d.deque ); ulong out_max = fd_ulong_min( queue_sz, FD_SYSVAR_RECENT_HASHES_CAP ); @@ -72,6 +72,6 @@ fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx ) { 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( fd_bank_block_hash_queue_query( slot_ctx->bank ), data ); + fd_sysvar_recent_hashes_encode( fd_bank_block_hash_queue_query( slot_ctx->bank ), 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 79b0e3583f..7554389f83 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h +++ b/src/flamenco/runtime/sysvar/fd_sysvar_recent_hashes.h @@ -5,6 +5,7 @@ account (address SysvarRecentB1ockHashes11111111111111111111). */ #include "fd_sysvar_base.h" +#include "../fd_blockhashes.h" /* FD_SYSVAR_RECENT_HASHES_CAP is the max number of block hash entries the recent blockhashes sysvar will include. @@ -29,6 +30,10 @@ fd_sysvar_recent_hashes_init( fd_exec_slot_ctx_t * slot_ctx ); void fd_sysvar_recent_hashes_update( fd_exec_slot_ctx_t * slot_ctx ); +void +fd_sysvar_recent_hashes_encode( fd_blockhashes_t const * bhq, + uchar out_mem[ FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ] ); + FD_PROTOTYPES_END #endif /* HEADER_fd_src_flamenco_runtime_sysvar_fd_sysvar_recent_hashes_h */ diff --git a/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c index 90afa012c9..5df23e4365 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c @@ -1,19 +1,10 @@ #include "fd_sysvar_recent_hashes.h" -#include "../../types/fd_types.h" FD_IMPORT_BINARY( example_recent_hashes, "src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.bin" ); static void test_sysvar_recent_hashes_bounds( void ) { - FD_TEST( example_recent_hashes_sz==FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); - fd_bincode_decode_ctx_t ctx = { - .data = example_recent_hashes, - .dataend = example_recent_hashes + example_recent_hashes_sz - }; - ulong obj_sz = 0UL; - FD_TEST( fd_recent_block_hashes_decode_footprint( &ctx, &obj_sz )==FD_BINCODE_SUCCESS ); - FD_TEST( obj_sz==FD_SYSVAR_RECENT_HASHES_FOOTPRINT ); - FD_TEST( fd_recent_block_hashes_align()==FD_SYSVAR_RECENT_HASHES_ALIGN ); + FD_TEST( FD_SYSVAR_RECENT_HASHES_BINCODE_SZ==6008 ); } static void diff --git a/src/flamenco/runtime/tests/harness/fd_block_harness.c b/src/flamenco/runtime/tests/harness/fd_block_harness.c index b50838d9c7..dcd13773e7 100644 --- a/src/flamenco/runtime/tests/harness/fd_block_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_block_harness.c @@ -1,4 +1,5 @@ #include "fd_block_harness.h" +#include "fd_harness_common.h" /* Stripped down version of `fd_refresh_vote_accounts()` that simply refreshes the stake delegation amount for each of the vote accounts using the stake delegations cache. */ @@ -329,8 +330,10 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, &pubkey ); } + fd_solfuzz_restore_lamports_per_signature( slot_ctx ); + /* Restore sysvar cache */ - FD_TEST( fd_sysvar_cache_restore( slot_ctx )==0 ); + fd_sysvar_cache_restore_fuzz( slot_ctx ); /* Refresh vote accounts to calculate stake delegations */ fd_runtime_fuzz_block_refresh_vote_accounts( vote_accounts_pool, @@ -404,16 +407,6 @@ fd_runtime_fuzz_block_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_hash_t * genesis_hash = fd_bank_genesis_hash_modify( slot_ctx->bank ); fd_memset( genesis_hash->hash, 0, sizeof(fd_hash_t) ); - // Use the latest lamports per signature - fd_block_block_hash_entry_t const * rbh = fd_sysvar_recent_hashes_join_const( sysvar_cache ); - if( FD_UNLIKELY( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh ) ) ) { - fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh ); - 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 ); - } - } - // Populate blockhash queue and recent blockhashes sysvar for( ushort i=0; iblockhash_queue_count; ++i ) { fd_hash_t hash; diff --git a/src/flamenco/runtime/tests/harness/fd_harness_common.c b/src/flamenco/runtime/tests/harness/fd_harness_common.c index d4f2c40533..642c3ac6a9 100644 --- a/src/flamenco/runtime/tests/harness/fd_harness_common.c +++ b/src/flamenco/runtime/tests/harness/fd_harness_common.c @@ -1,4 +1,7 @@ #include "fd_harness_common.h" +#include "../../fd_system_ids.h" +#include "../../context/fd_exec_slot_ctx.h" +#include "../../sysvar/fd_sysvar_recent_hashes.h" ulong fd_runtime_fuzz_runner_align( void ) { @@ -130,3 +133,77 @@ fd_runtime_fuzz_restore_features( fd_features_t * features, } return 1; } + +/* Below is completely nonsensical. These solfuzz routines only exist + to keep compatibility with very broken behavior that was once added + by someone who did not understand sysvar and bank data structures. */ + +/* Peek the newest 'blockhash' + 'lamports per signature' value of the + 'recent blockhashes' sysvar account even if the sysvar account is + oversize. + However, ignore the value if the sysvar account's length prefix is + larger than the account size. This logic is nonsense. */ + +void +fd_solfuzz_restore_lamports_per_signature( fd_exec_slot_ctx_t * slot_ctx ) { + FD_TXN_ACCOUNT_DECL( rec ); + int db_ok = fd_txn_account_init_from_funk_readonly( rec, &fd_sysvar_recent_block_hashes_id, slot_ctx->funk, slot_ctx->funk_txn ); + if( db_ok!=FD_ACC_MGR_SUCCESS ) return; + if( FD_UNLIKELY( rec->vt->get_lamports( rec )==0 ) ) return; + uchar const * const data = rec->vt->get_data( rec ); + ulong const data_sz = rec->vt->get_data_len( rec ); + + /* Peek the RBH sysvar. The first 8 bytes is a length prefix, which + is followed by a sequence of 40 byte large objects. Read the first + entry, which is the newest one. */ + if( FD_UNLIKELY( data_sz<8UL ) ) return; + ulong const entry_cnt = FD_LOAD( ulong, data ); + if( FD_UNLIKELY( !entry_cnt ) ) return; + ulong serialized_sz; + if( FD_UNLIKELY( __builtin_umull_overflow( entry_cnt, 40UL, &serialized_sz ) ) ) return; + if( FD_UNLIKELY( __builtin_uaddl_overflow( serialized_sz, 8UL, &serialized_sz ) ) ) return; + if( FD_UNLIKELY( serialized_sz>data_sz ) ) return; + + /* Update bank fields */ + ulong lamports_per_sig = FD_LOAD( ulong, data+40UL ); + fd_bank_lamports_per_signature_set ( slot_ctx->bank, lamports_per_sig ); + fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, lamports_per_sig ); +} + +void +fd_solfuzz_restore_instr_blockhash_queue( fd_exec_slot_ctx_t * slot_ctx ) { + fd_blockhashes_t * blockhashes = fd_bank_block_hash_queue_modify( slot_ctx->bank ); + fd_blockhashes_init( blockhashes, blockhashes->map->seed ); /* clear */ + + /* Peek the RBH sysvar. Read the last entry, which is the oldest one. */ + FD_TXN_ACCOUNT_DECL( rec ); + int db_ok = fd_txn_account_init_from_funk_readonly( rec, &fd_sysvar_recent_block_hashes_id, slot_ctx->funk, slot_ctx->funk_txn ); + if( db_ok!=FD_ACC_MGR_SUCCESS ) return; + if( FD_UNLIKELY( rec->vt->get_lamports( rec )==0 ) ) return; + uchar const * const acc_data = rec->vt->get_data( rec ); + ulong const acc_data_sz = rec->vt->get_data_len( rec ); + if( FD_UNLIKELY( acc_data_sz<8UL ) ) return; + ulong const entry_cnt = FD_LOAD( ulong, acc_data ); + if( FD_UNLIKELY( !entry_cnt ) ) return; + ulong serialized_sz; + if( FD_UNLIKELY( __builtin_umull_overflow( entry_cnt, 40UL, &serialized_sz ) ) ) return; + if( FD_UNLIKELY( __builtin_uaddl_overflow( serialized_sz, 8UL, &serialized_sz ) ) ) return; + if( FD_UNLIKELY( serialized_sz>acc_data_sz ) ) return; + fd_hash_t blockhash = FD_LOAD( fd_hash_t, acc_data+serialized_sz-40UL ); + ulong lamports_per_sig = FD_LOAD( ulong, acc_data+serialized_sz- 8UL ); + + /* Update the bank's blockhash queue (write the first/only entry) */ + fd_blockhash_info_t * info = fd_blockhashes_push_new( blockhashes, &blockhash ); + info->fee_calculator = (fd_fee_calculator_t) { .lamports_per_signature = lamports_per_sig }; + fd_bank_lamports_per_signature_set ( slot_ctx->bank, lamports_per_sig ); + fd_bank_prev_lamports_per_signature_set( slot_ctx->bank, lamports_per_sig ); + + /* Update the sysvar cache's object and data content, and the RBH + sysvar account. */ + 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_sysvar_recent_hashes_encode( fd_bank_block_hash_queue_query( slot_ctx->bank ), 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/tests/harness/fd_harness_common.h b/src/flamenco/runtime/tests/harness/fd_harness_common.h index 0f7240e42f..07652ccb5f 100644 --- a/src/flamenco/runtime/tests/harness/fd_harness_common.h +++ b/src/flamenco/runtime/tests/harness/fd_harness_common.h @@ -72,6 +72,14 @@ int fd_runtime_fuzz_restore_features( fd_features_t * features, fd_exec_test_feature_set_t const * feature_set ); +/* Awful hack -- see the function definition for what these do. */ + +void +fd_solfuzz_restore_lamports_per_signature( fd_exec_slot_ctx_t * slot_ctx ); + +void +fd_solfuzz_restore_instr_blockhash_queue( fd_exec_slot_ctx_t * slot_ctx ); + FD_PROTOTYPES_END #endif /* HEADER_fd_src_flamenco_runtime_tests_harness_fd_harness_common_h */ diff --git a/src/flamenco/runtime/tests/harness/fd_instr_harness.c b/src/flamenco/runtime/tests/harness/fd_instr_harness.c index 3c5c9c6ad9..dfca70de3f 100644 --- a/src/flamenco/runtime/tests/harness/fd_instr_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_instr_harness.c @@ -196,8 +196,10 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, } } + fd_solfuzz_restore_lamports_per_signature( slot_ctx ); + /* Restore sysvar cache */ - FD_TEST( fd_sysvar_cache_restore( slot_ctx )==0 ); + fd_sysvar_cache_restore_fuzz( slot_ctx ); ctx->sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); /* Fill missing sysvar cache values with defaults */ @@ -254,20 +256,7 @@ fd_runtime_fuzz_instr_ctx_create( fd_runtime_fuzz_runner_t * runner, } /* Override most recent blockhash if given */ - fd_block_block_hash_entry_t const * rbh = fd_sysvar_recent_hashes_join_const( sysvar_cache ); - if( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh ) ) { - fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_tail_const( rbh ); - if( last ) { - fd_blockhashes_t * blockhashes = fd_bank_block_hash_queue_modify( slot_ctx->bank ); - fd_blockhashes_pop_new( blockhashes ); - fd_blockhash_info_t * info = fd_blockhashes_push_new( blockhashes, &last->blockhash ); - info->fee_calculator = last->fee_calculator; - - 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 ); - } - } + fd_solfuzz_restore_instr_blockhash_queue( slot_ctx ); /* 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 69bb2b056b..c0a031190e 100644 --- a/src/flamenco/runtime/tests/harness/fd_txn_harness.c +++ b/src/flamenco/runtime/tests/harness/fd_txn_harness.c @@ -16,7 +16,6 @@ static fd_txn_p_t * fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, fd_exec_slot_ctx_t * slot_ctx, fd_exec_test_txn_context_t const * test_ctx ) { - const uchar empty_bytes[64] = { 0 }; fd_funk_t * funk = runner->funk; /* Generate unique ID for funk txn */ @@ -85,9 +84,10 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, fee_rate_governor->target_signatures_per_slot = 20000; fd_bank_ticks_per_slot_set( slot_ctx->bank, 64 ); + fd_solfuzz_restore_lamports_per_signature( slot_ctx ); /* Restore sysvars from account context */ - FD_TEST( fd_sysvar_cache_restore( slot_ctx )==0 ); + fd_sysvar_cache_restore_fuzz( slot_ctx ); fd_sysvar_cache_t * sysvar_cache = fd_bank_sysvar_cache_modify( slot_ctx->bank ); /* Set epoch bank variables if not present (defaults obtained from GenesisConfig::default() in Agave) */ @@ -153,8 +153,9 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, the epoch rewards sysvar, we may need to update this. */ if( !fd_sysvar_epoch_rewards_is_valid( sysvar_cache ) ) { - 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, 0UL, 0UL, last_hash ); + fd_hash_t last_hash = {0}; + if( test_ctx->blockhash_queue_count > 0 ) last_hash = FD_LOAD( fd_hash_t, test_ctx->blockhash_queue[0]->bytes ); + fd_sysvar_epoch_rewards_init( slot_ctx, 0UL, 2UL, 1UL, 0UL, 0UL, &last_hash ); } /* Blockhash queue is given in txn message. We need to populate the following two fields: @@ -166,16 +167,6 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, ulong blockhash_seed; FD_TEST( fd_rng_secure( &blockhash_seed, sizeof(ulong) ) ); fd_blockhashes_t * blockhashes = fd_blockhashes_init( fd_bank_block_hash_queue_modify( slot_ctx->bank ), blockhash_seed ); - // Save lamports per signature for most recent blockhash, if sysvar cache contains recent block hashes - fd_block_block_hash_entry_t const * rbh = fd_sysvar_recent_hashes_join_const( sysvar_cache ); - if( FD_UNLIKELY( rbh && !deq_fd_block_block_hash_entry_t_empty( rbh ) ) ) { - fd_block_block_hash_entry_t const * last = deq_fd_block_block_hash_entry_t_peek_head_const( rbh ); - 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 ); - } - } - // Blockhash_queue[end] = last (latest) hash // Blockhash_queue[0] = genesis hash if( num_blockhashes > 0 ) { @@ -196,11 +187,8 @@ fd_runtime_fuzz_txn_ctx_create( fd_runtime_fuzz_runner_t * runner, } else { // Add a default empty blockhash and use it as genesis num_blockhashes = 1; - fd_hash_t * genesis_hash = fd_bank_genesis_hash_modify( slot_ctx->bank ); - memcpy( genesis_hash->hash, empty_bytes, sizeof(fd_hash_t) ); - 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_bank_genesis_hash_modify( slot_ctx->bank ) = (fd_hash_t){0}; + fd_bank_poh_set( slot_ctx->bank, (fd_hash_t){0} ); fd_sysvar_recent_hashes_update( slot_ctx ); } @@ -268,7 +256,6 @@ fd_runtime_fuzz_serialize_txn( uchar * txn_ fd_exec_test_sanitized_transaction_t const * tx, ushort * out_instr_cnt, ushort * out_addr_table_cnt ) { - const uchar empty_bytes[64] = { 0 }; uchar * txn_raw_cur_ptr = txn_raw_begin; /* Compact array of signatures (https://solana.com/docs/core/transactions#transaction) @@ -279,7 +266,9 @@ fd_runtime_fuzz_serialize_txn( uchar * txn_ uchar signature_cnt = fd_uchar_max( 1, (uchar) tx->signatures_count ); FD_CHECKED_ADD_TO_TXN_DATA( txn_raw_begin, &txn_raw_cur_ptr, &signature_cnt, sizeof(uchar) ); for( uchar i = 0; i < signature_cnt; ++i ) { - FD_CHECKED_ADD_TO_TXN_DATA( txn_raw_begin, &txn_raw_cur_ptr, tx->signatures && tx->signatures[i] ? tx->signatures[i]->bytes : empty_bytes, FD_TXN_SIGNATURE_SZ ); + fd_signature_t sig = {0}; + if( tx->signatures && tx->signatures[i] ) sig = FD_LOAD( fd_signature_t, tx->signatures[i]->bytes ); + FD_CHECKED_ADD_TO_TXN_DATA( txn_raw_begin, &txn_raw_cur_ptr, &sig, FD_TXN_SIGNATURE_SZ ); } /* Message */ @@ -309,7 +298,9 @@ fd_runtime_fuzz_serialize_txn( uchar * txn_ /* Recent blockhash (32 bytes) (https://solana.com/docs/core/transactions#recent-blockhash) */ // Note: add an empty blockhash if none is provided - FD_CHECKED_ADD_TO_TXN_DATA( txn_raw_begin, &txn_raw_cur_ptr, tx->message.recent_blockhash ? tx->message.recent_blockhash->bytes : empty_bytes, sizeof(fd_hash_t) ); + fd_hash_t msg_rbh = {0}; + if( tx->message.recent_blockhash ) msg_rbh = FD_LOAD( fd_hash_t, tx->message.recent_blockhash->bytes ); + FD_CHECKED_ADD_TO_TXN_DATA( txn_raw_begin, &txn_raw_cur_ptr, &msg_rbh, sizeof(fd_hash_t) ); /* Compact array of instructions (https://solana.com/docs/core/transactions#array-of-instructions) */ // Instruction count is a compact u16 diff --git a/src/flamenco/types/fd_fuzz_types.h b/src/flamenco/types/fd_fuzz_types.h index 949aa36a3d..56a90eeb17 100644 --- a/src/flamenco/types/fd_fuzz_types.h +++ b/src/flamenco/types/fd_fuzz_types.h @@ -1389,29 +1389,6 @@ void *fd_slot_hashes_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) { return mem; } -void *fd_block_block_hash_entry_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) { - fd_block_block_hash_entry_t *self = (fd_block_block_hash_entry_t *) mem; - *alloc_mem = (uchar *) *alloc_mem + sizeof(fd_block_block_hash_entry_t); - fd_block_block_hash_entry_new(mem); - fd_hash_generate( &self->blockhash, alloc_mem, rng ); - fd_fee_calculator_generate( &self->fee_calculator, alloc_mem, rng ); - return mem; -} - -void *fd_recent_block_hashes_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) { - fd_recent_block_hashes_t *self = (fd_recent_block_hashes_t *) mem; - *alloc_mem = (uchar *) *alloc_mem + sizeof(fd_recent_block_hashes_t); - fd_recent_block_hashes_new(mem); - ulong hashes_len = fd_rng_ulong( rng ) % 8; - ulong hashes_max = fd_ulong_max( hashes_len, 151 ); - self->hashes = deq_fd_block_block_hash_entry_t_join_new( alloc_mem, hashes_max ); - for( ulong i=0; i < hashes_len; i++ ) { - fd_block_block_hash_entry_t * elem = deq_fd_block_block_hash_entry_t_push_tail_nocopy( self->hashes ); - fd_block_block_hash_entry_generate( elem, alloc_mem, rng ); - } - return mem; -} - void *fd_slot_meta_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) { fd_slot_meta_t *self = (fd_slot_meta_t *) mem; *alloc_mem = (uchar *) *alloc_mem + sizeof(fd_slot_meta_t); diff --git a/src/flamenco/types/fd_types.c b/src/flamenco/types/fd_types.c index edfdbcfce8..276095aa19 100644 --- a/src/flamenco/types/fd_types.c +++ b/src/flamenco/types/fd_types.c @@ -8607,192 +8607,6 @@ ulong fd_slot_hashes_size_global( fd_slot_hashes_global_t const * self ) { return size; } -int fd_block_block_hash_entry_encode( fd_block_block_hash_entry_t const * self, fd_bincode_encode_ctx_t * ctx ) { - int err; - err = fd_hash_encode( &self->blockhash, ctx ); - if( FD_UNLIKELY( err ) ) return err; - err = fd_fee_calculator_encode( &self->fee_calculator, ctx ); - if( FD_UNLIKELY( err ) ) return err; - return FD_BINCODE_SUCCESS; -} -static inline int fd_block_block_hash_entry_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { - if( (ulong)ctx->data + 40UL > (ulong)ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; - ctx->data = (void *)( (ulong)ctx->data + 40UL ); - return 0; -} -static void fd_block_block_hash_entry_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { - fd_block_block_hash_entry_t * self = (fd_block_block_hash_entry_t *)struct_mem; - fd_hash_decode_inner( &self->blockhash, alloc_mem, ctx ); - fd_fee_calculator_decode_inner( &self->fee_calculator, alloc_mem, ctx ); -} -void * fd_block_block_hash_entry_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) { - fd_block_block_hash_entry_t * self = (fd_block_block_hash_entry_t *)mem; - fd_block_block_hash_entry_new( self ); - void * alloc_region = (uchar *)mem + sizeof(fd_block_block_hash_entry_t); - void * * alloc_mem = &alloc_region; - fd_block_block_hash_entry_decode_inner( mem, alloc_mem, ctx ); - return self; -} -void fd_block_block_hash_entry_walk( void * w, fd_block_block_hash_entry_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_block_hash_entry", level++, 0 ); - fd_hash_walk( w, &self->blockhash, fun, "blockhash", level, 0 ); - fd_fee_calculator_walk( w, &self->fee_calculator, fun, "fee_calculator", level, 0 ); - fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_block_block_hash_entry", level--, 0 ); -} -int fd_recent_block_hashes_encode( fd_recent_block_hashes_t const * self, fd_bincode_encode_ctx_t * ctx ) { - int err; - if( self->hashes ) { - ulong hashes_len = deq_fd_block_block_hash_entry_t_cnt( self->hashes ); - err = fd_bincode_uint64_encode( hashes_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( deq_fd_block_block_hash_entry_t_iter_t iter = deq_fd_block_block_hash_entry_t_iter_init( self->hashes ); !deq_fd_block_block_hash_entry_t_iter_done( self->hashes, iter ); iter = deq_fd_block_block_hash_entry_t_iter_next( self->hashes, iter ) ) { - fd_block_block_hash_entry_t const * ele = deq_fd_block_block_hash_entry_t_iter_ele_const( self->hashes, iter ); - err = fd_block_block_hash_entry_encode( ele, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - } else { - ulong hashes_len = 0; - err = fd_bincode_uint64_encode( hashes_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - return FD_BINCODE_SUCCESS; -} -int fd_recent_block_hashes_encode_global( fd_recent_block_hashes_global_t const * self, fd_bincode_encode_ctx_t * ctx ) { - int err; - if( self->hashes_offset ) { - uchar * hashes_laddr = (uchar*)self + self->hashes_offset; - fd_block_block_hash_entry_t * hashes = deq_fd_block_block_hash_entry_t_join( hashes_laddr ); - ulong hashes_len = deq_fd_block_block_hash_entry_t_cnt( hashes ); - err = fd_bincode_uint64_encode( hashes_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( deq_fd_block_block_hash_entry_t_iter_t iter = deq_fd_block_block_hash_entry_t_iter_init( hashes ); !deq_fd_block_block_hash_entry_t_iter_done( hashes, iter ); iter = deq_fd_block_block_hash_entry_t_iter_next( hashes, iter ) ) { - fd_block_block_hash_entry_t const * ele = deq_fd_block_block_hash_entry_t_iter_ele_const( hashes, iter ); - err = fd_block_block_hash_entry_encode( ele, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - } else { - ulong hashes_len = 0; - err = fd_bincode_uint64_encode( hashes_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - return FD_BINCODE_SUCCESS; -} -static int fd_recent_block_hashes_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; - ulong hashes_len; - err = fd_bincode_uint64_decode( &hashes_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - ulong hashes_max = fd_ulong_max( hashes_len, 151 ); - *total_sz += deq_fd_block_block_hash_entry_t_align() + deq_fd_block_block_hash_entry_t_footprint( hashes_max ); - ulong hashes_sz; - if( FD_UNLIKELY( __builtin_umull_overflow( hashes_len, 40, &hashes_sz ) ) ) return FD_BINCODE_ERR_UNDERFLOW; - err = fd_bincode_bytes_decode_footprint( hashes_sz, ctx ); - if( FD_UNLIKELY( err ) ) return err; - return 0; -} -int fd_recent_block_hashes_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { - *total_sz += sizeof(fd_recent_block_hashes_t); - void const * start_data = ctx->data; - int err = fd_recent_block_hashes_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_recent_block_hashes_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { - fd_recent_block_hashes_t * self = (fd_recent_block_hashes_t *)struct_mem; - ulong hashes_len; - fd_bincode_uint64_decode_unsafe( &hashes_len, ctx ); - ulong hashes_max = fd_ulong_max( hashes_len, 151 ); - self->hashes = deq_fd_block_block_hash_entry_t_join_new( alloc_mem, hashes_max ); - for( ulong i=0; i < hashes_len; i++ ) { - fd_block_block_hash_entry_t * elem = deq_fd_block_block_hash_entry_t_push_tail_nocopy( self->hashes ); - fd_block_block_hash_entry_new( elem ); - fd_block_block_hash_entry_decode_inner( elem, alloc_mem, ctx ); - } -} -void * fd_recent_block_hashes_decode( void * mem, fd_bincode_decode_ctx_t * ctx ) { - fd_recent_block_hashes_t * self = (fd_recent_block_hashes_t *)mem; - fd_recent_block_hashes_new( self ); - void * alloc_region = (uchar *)mem + sizeof(fd_recent_block_hashes_t); - void * * alloc_mem = &alloc_region; - fd_recent_block_hashes_decode_inner( mem, alloc_mem, ctx ); - return self; -} -static void fd_recent_block_hashes_decode_inner_global( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) { - fd_recent_block_hashes_global_t * self = (fd_recent_block_hashes_global_t *)struct_mem; - ulong hashes_len; - fd_bincode_uint64_decode_unsafe( &hashes_len, ctx ); - *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, deq_fd_block_block_hash_entry_t_align() ); - ulong hashes_max = fd_ulong_max( hashes_len, 151 ); - fd_block_block_hash_entry_t * hashes = deq_fd_block_block_hash_entry_t_join_new( alloc_mem, hashes_max ); - for( ulong i=0; i < hashes_len; i++ ) { - fd_block_block_hash_entry_t * elem = deq_fd_block_block_hash_entry_t_push_tail_nocopy( hashes ); - fd_block_block_hash_entry_new( (fd_block_block_hash_entry_t*)fd_type_pun( elem ) ); - fd_block_block_hash_entry_decode_inner( elem, alloc_mem, ctx ); - } - self->hashes_offset = (ulong)deq_fd_block_block_hash_entry_t_leave( hashes ) - (ulong)struct_mem; -} -void * fd_recent_block_hashes_decode_global( void * mem, fd_bincode_decode_ctx_t * ctx ) { - fd_recent_block_hashes_global_t * self = (fd_recent_block_hashes_global_t *)mem; - fd_recent_block_hashes_new( (fd_recent_block_hashes_t *)self ); - void * alloc_region = (uchar *)mem + sizeof(fd_recent_block_hashes_global_t); - void * * alloc_mem = &alloc_region; - fd_recent_block_hashes_decode_inner_global( mem, alloc_mem, ctx ); - return self; -} -void fd_recent_block_hashes_new(fd_recent_block_hashes_t * self) { - fd_memset( self, 0, sizeof(fd_recent_block_hashes_t) ); -} -void fd_recent_block_hashes_walk( void * w, fd_recent_block_hashes_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_recent_block_hashes", level++, 0 ); - - /* Walk deque */ - fun( w, self->hashes, "hashes", FD_FLAMENCO_TYPE_ARR, "hashes", level++, 0 ); - if( self->hashes ) { - for( deq_fd_block_block_hash_entry_t_iter_t iter = deq_fd_block_block_hash_entry_t_iter_init( self->hashes ); - !deq_fd_block_block_hash_entry_t_iter_done( self->hashes, iter ); - iter = deq_fd_block_block_hash_entry_t_iter_next( self->hashes, iter ) ) { - fd_block_block_hash_entry_t * ele = deq_fd_block_block_hash_entry_t_iter_ele( self->hashes, iter ); - fd_block_block_hash_entry_walk(w, ele, fun, "hashes", level, 0 ); - } - } - fun( w, self->hashes, "hashes", FD_FLAMENCO_TYPE_ARR_END, "hashes", level--, 0 ); - /* Done walking deque */ - - fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_recent_block_hashes", level--, 0 ); -} -ulong fd_recent_block_hashes_size( fd_recent_block_hashes_t const * self ) { - ulong size = 0; - if( self->hashes ) { - size += sizeof(ulong); - for( deq_fd_block_block_hash_entry_t_iter_t iter = deq_fd_block_block_hash_entry_t_iter_init( self->hashes ); !deq_fd_block_block_hash_entry_t_iter_done( self->hashes, iter ); iter = deq_fd_block_block_hash_entry_t_iter_next( self->hashes, iter ) ) { - fd_block_block_hash_entry_t * ele = deq_fd_block_block_hash_entry_t_iter_ele( self->hashes, iter ); - size += fd_block_block_hash_entry_size( ele ); - } - } else { - size += sizeof(ulong); - } - return size; -} - -ulong fd_recent_block_hashes_size_global( fd_recent_block_hashes_global_t const * self ) { - ulong size = 0; - if( self->hashes_offset!=0 ) { - fd_block_block_hash_entry_t * hashes = (fd_block_block_hash_entry_t *)deq_fd_block_block_hash_entry_t_join( fd_type_pun( (uchar *)self + self->hashes_offset ) ); - size += sizeof(ulong); - for( deq_fd_block_block_hash_entry_t_iter_t iter = deq_fd_block_block_hash_entry_t_iter_init( hashes ); !deq_fd_block_block_hash_entry_t_iter_done( hashes, iter ); iter = deq_fd_block_block_hash_entry_t_iter_next( hashes, iter ) ) { - fd_block_block_hash_entry_t * ele = deq_fd_block_block_hash_entry_t_iter_ele( hashes, iter ); - size += fd_block_block_hash_entry_size( ele ); - } - } else { - size += sizeof(ulong); - } - return size; -} - int fd_slot_meta_encode( fd_slot_meta_t const * self, fd_bincode_encode_ctx_t * ctx ) { int err; err = fd_bincode_uint64_encode( self->slot, ctx ); diff --git a/src/flamenco/types/fd_types.h b/src/flamenco/types/fd_types.h index 155fd237ee..ac762d235e 100644 --- a/src/flamenco/types/fd_types.h +++ b/src/flamenco/types/fd_types.h @@ -1617,45 +1617,6 @@ typedef struct fd_slot_hashes_global fd_slot_hashes_global_t; static FD_FN_UNUSED fd_slot_hash_t * fd_slot_hashes_hashes_join( fd_slot_hashes_global_t * type ) { // deque return type->hashes_offset ? (fd_slot_hash_t *)deq_fd_slot_hash_t_join( fd_type_pun( (uchar *)type + type->hashes_offset ) ) : NULL; } -/* Encoded Size: Fixed (40 bytes) */ -struct fd_block_block_hash_entry { - fd_hash_t blockhash; - fd_fee_calculator_t fee_calculator; -}; -typedef struct fd_block_block_hash_entry fd_block_block_hash_entry_t; -#define FD_BLOCK_BLOCK_HASH_ENTRY_ALIGN alignof(fd_block_block_hash_entry_t) - -#define DEQUE_NAME deq_fd_block_block_hash_entry_t -#define DEQUE_T fd_block_block_hash_entry_t -#include "../../util/tmpl/fd_deque_dynamic.c" -#undef DEQUE_NAME -#undef DEQUE_T -#undef DEQUE_MAX -static inline fd_block_block_hash_entry_t * -deq_fd_block_block_hash_entry_t_join_new( void * * alloc_mem, ulong max ) { - if( FD_UNLIKELY( 0 == max ) ) max = 1; // prevent underflow - *alloc_mem = (void*)fd_ulong_align_up( (ulong)*alloc_mem, deq_fd_block_block_hash_entry_t_align() ); - void * deque_mem = *alloc_mem; - *alloc_mem = (uchar *)*alloc_mem + deq_fd_block_block_hash_entry_t_footprint( max ); - return deq_fd_block_block_hash_entry_t_join( deq_fd_block_block_hash_entry_t_new( deque_mem, max ) ); -} - -/* Encoded Size: Dynamic */ -struct fd_recent_block_hashes { - fd_block_block_hash_entry_t * hashes; /* fd_deque_dynamic (min cnt 151) */ -}; -typedef struct fd_recent_block_hashes fd_recent_block_hashes_t; -#define FD_RECENT_BLOCK_HASHES_ALIGN alignof(fd_recent_block_hashes_t) - -struct fd_recent_block_hashes_global { - ulong hashes_offset; /* fd_deque_dynamic (min cnt 151) */ -}; -typedef struct fd_recent_block_hashes_global fd_recent_block_hashes_global_t; -#define FD_RECENT_BLOCK_HASHES_GLOBAL_ALIGN alignof(fd_recent_block_hashes_global_t) - -static FD_FN_UNUSED fd_block_block_hash_entry_t * fd_recent_block_hashes_hashes_join( fd_recent_block_hashes_global_t * type ) { // deque - return type->hashes_offset ? (fd_block_block_hash_entry_t *)deq_fd_block_block_hash_entry_t_join( fd_type_pun( (uchar *)type + type->hashes_offset ) ) : NULL; -} /* Encoded Size: Dynamic */ struct fd_slot_meta { ulong slot; @@ -4493,29 +4454,6 @@ void * fd_slot_hashes_decode_global( void * mem, fd_bincode_decode_ctx_t * ctx ) int fd_slot_hashes_encode_global( fd_slot_hashes_global_t const * self, fd_bincode_encode_ctx_t * ctx ); ulong fd_slot_hashes_size_global( fd_slot_hashes_global_t const * self ); -static inline void fd_block_block_hash_entry_new( fd_block_block_hash_entry_t * self ) { fd_memset( self, 0, sizeof(fd_block_block_hash_entry_t) ); } -int fd_block_block_hash_entry_encode( fd_block_block_hash_entry_t const * self, fd_bincode_encode_ctx_t * ctx ); -void fd_block_block_hash_entry_walk( void * w, fd_block_block_hash_entry_t const * self, fd_types_walk_fn_t fun, const char *name, uint level, uint varint ); -static inline ulong fd_block_block_hash_entry_size( fd_block_block_hash_entry_t const * self ) { (void)self; return 40UL; } -static inline ulong fd_block_block_hash_entry_align( void ) { return FD_BLOCK_BLOCK_HASH_ENTRY_ALIGN; } -static inline int fd_block_block_hash_entry_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) { - *total_sz += sizeof(fd_block_block_hash_entry_t); - if( (ulong)ctx->data + 40UL > (ulong)ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; }; - return 0; -} -void * fd_block_block_hash_entry_decode( void * mem, fd_bincode_decode_ctx_t * ctx ); - -void fd_recent_block_hashes_new( fd_recent_block_hashes_t * self ); -int fd_recent_block_hashes_encode( fd_recent_block_hashes_t const * self, fd_bincode_encode_ctx_t * ctx ); -void fd_recent_block_hashes_walk( void * w, fd_recent_block_hashes_t const * self, fd_types_walk_fn_t fun, const char *name, uint level, uint varint ); -ulong fd_recent_block_hashes_size( fd_recent_block_hashes_t const * self ); -static inline ulong fd_recent_block_hashes_align( void ) { return FD_RECENT_BLOCK_HASHES_ALIGN; } -int fd_recent_block_hashes_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ); -void * fd_recent_block_hashes_decode( void * mem, fd_bincode_decode_ctx_t * ctx ); -void * fd_recent_block_hashes_decode_global( void * mem, fd_bincode_decode_ctx_t * ctx ); -int fd_recent_block_hashes_encode_global( fd_recent_block_hashes_global_t const * self, fd_bincode_encode_ctx_t * ctx ); -ulong fd_recent_block_hashes_size_global( fd_recent_block_hashes_global_t const * self ); - void fd_slot_meta_new( fd_slot_meta_t * self ); int fd_slot_meta_encode( fd_slot_meta_t const * self, fd_bincode_encode_ctx_t * ctx ); void fd_slot_meta_walk( void * w, fd_slot_meta_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 655caf53d7..1d0695c576 100644 --- a/src/flamenco/types/fd_types.json +++ b/src/flamenco/types/fd_types.json @@ -914,22 +914,6 @@ ], "comment": "https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/slot_hashes.rs#L31" }, - { - "name": "block_block_hash_entry", - "type": "struct", - "fields": [ - { "name": "blockhash", "type": "hash" }, - { "name": "fee_calculator", "type": "fee_calculator" } - ] - }, - { - "name": "recent_block_hashes", - "type": "struct", - "global": true, - "fields": [ - { "name": "hashes", "type": "deque", "element": "block_block_hash_entry", "min": 151 } - ] - }, { "name": "slot_meta", "type": "struct", diff --git a/src/flamenco/types/fd_types_reflect_generated.c b/src/flamenco/types/fd_types_reflect_generated.c index d9f7d6cb6f..63f3c3bfa5 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 = 248; +ulong fd_types_vt_list_cnt = 246; 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 }, @@ -93,8 +93,6 @@ fd_types_vt_t const fd_types_vt_list[] = { { .name="fd_slot_history", .name_len=15, .align=FD_SLOT_HISTORY_ALIGN, .new_=(void *)fd_slot_history_new, .decode=(void *)fd_slot_history_decode, .size=(void *)fd_slot_history_size, .walk=(void *)fd_slot_history_walk, .decode_footprint=(void *)fd_slot_history_decode_footprint, .encode=(void *)fd_slot_history_encode }, { .name="fd_slot_hash", .name_len=12, .align=FD_SLOT_HASH_ALIGN, .new_=(void *)fd_slot_hash_new, .decode=(void *)fd_slot_hash_decode, .size=(void *)fd_slot_hash_size, .walk=(void *)fd_slot_hash_walk, .decode_footprint=(void *)fd_slot_hash_decode_footprint, .encode=(void *)fd_slot_hash_encode }, { .name="fd_slot_hashes", .name_len=14, .align=FD_SLOT_HASHES_ALIGN, .new_=(void *)fd_slot_hashes_new, .decode=(void *)fd_slot_hashes_decode, .size=(void *)fd_slot_hashes_size, .walk=(void *)fd_slot_hashes_walk, .decode_footprint=(void *)fd_slot_hashes_decode_footprint, .encode=(void *)fd_slot_hashes_encode }, - { .name="fd_block_block_hash_entry", .name_len=25, .align=FD_BLOCK_BLOCK_HASH_ENTRY_ALIGN, .new_=(void *)fd_block_block_hash_entry_new, .decode=(void *)fd_block_block_hash_entry_decode, .size=(void *)fd_block_block_hash_entry_size, .walk=(void *)fd_block_block_hash_entry_walk, .decode_footprint=(void *)fd_block_block_hash_entry_decode_footprint, .encode=(void *)fd_block_block_hash_entry_encode }, - { .name="fd_recent_block_hashes", .name_len=22, .align=FD_RECENT_BLOCK_HASHES_ALIGN, .new_=(void *)fd_recent_block_hashes_new, .decode=(void *)fd_recent_block_hashes_decode, .size=(void *)fd_recent_block_hashes_size, .walk=(void *)fd_recent_block_hashes_walk, .decode_footprint=(void *)fd_recent_block_hashes_decode_footprint, .encode=(void *)fd_recent_block_hashes_encode }, { .name="fd_slot_meta", .name_len=12, .align=FD_SLOT_META_ALIGN, .new_=(void *)fd_slot_meta_new, .decode=(void *)fd_slot_meta_decode, .size=(void *)fd_slot_meta_size, .walk=(void *)fd_slot_meta_walk, .decode_footprint=(void *)fd_slot_meta_decode_footprint, .encode=(void *)fd_slot_meta_encode }, { .name="fd_clock_timestamp_vote", .name_len=23, .align=FD_CLOCK_TIMESTAMP_VOTE_ALIGN, .new_=(void *)fd_clock_timestamp_vote_new, .decode=(void *)fd_clock_timestamp_vote_decode, .size=(void *)fd_clock_timestamp_vote_size, .walk=(void *)fd_clock_timestamp_vote_walk, .decode_footprint=(void *)fd_clock_timestamp_vote_decode_footprint, .encode=(void *)fd_clock_timestamp_vote_encode }, { .name="fd_clock_timestamp_votes", .name_len=24, .align=FD_CLOCK_TIMESTAMP_VOTES_ALIGN, .new_=(void *)fd_clock_timestamp_votes_new, .decode=(void *)fd_clock_timestamp_votes_decode, .size=(void *)fd_clock_timestamp_votes_size, .walk=(void *)fd_clock_timestamp_votes_walk, .decode_footprint=(void *)fd_clock_timestamp_votes_decode_footprint, .encode=(void *)fd_clock_timestamp_votes_encode }, From 2e83519c2a46442348ad3de832f3baea771c4b50 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Fri, 25 Jul 2025 01:39:38 +0000 Subject: [PATCH 4/5] Add .solcap and .tar.zst to .gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e3955c081b..987cf91aab 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,9 @@ compile_commands.json # Dependencies opt/ opt-msan/ -deps-bundle.tar.zst + +# Archives +*.tar.zst # Nix /result @@ -52,6 +54,7 @@ deps-bundle.tar.zst # Packet Captures *.pcap *.pcapng +*.solcap # Logs *.log From 5fcc60710b7f089e6e801ce1f934ebf5f9e77fde Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Mon, 28 Jul 2025 11:55:18 +0000 Subject: [PATCH 5/5] runtime: sysvar cache tests --- .../runtime/sysvar/fd_sysvar_epoch_schedule.c | 2 +- src/flamenco/runtime/sysvar/test_sysvar.c | 16 +- .../runtime/sysvar/test_sysvar_cache.c | 210 ++++++++++++++++++ .../runtime/sysvar/test_sysvar_cache_util.h | 38 ++++ .../sysvar/test_sysvar_epoch_schedule.c | 41 ++++ .../sysvar/test_sysvar_recent_hashes.c | 118 +++++++++- .../sysvar/test_sysvar_stake_history.c | 57 ++++- src/flamenco/types/fd_types_custom.h | 8 + 8 files changed, 483 insertions(+), 7 deletions(-) create mode 100644 src/flamenco/runtime/sysvar/test_sysvar_cache_util.h diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c index 4fbc78c200..1455379062 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_epoch_schedule.c @@ -107,7 +107,7 @@ fd_slot_to_epoch( fd_epoch_schedule_t const * schedule, return epoch; } -/* https://github.com/firedancer-io/solana/blob/dab3da8e7b667d7527565bddbdbecf7ec1fb868e/sdk/program/src/epoch_schedule.rs#L114 */ +/* https://docs.rs/solana-epoch-schedule/2.2.1/src/solana_epoch_schedule/lib.rs.html#136-151 */ ulong fd_slot_to_leader_schedule_epoch( fd_epoch_schedule_t const * schedule, diff --git a/src/flamenco/runtime/sysvar/test_sysvar.c b/src/flamenco/runtime/sysvar/test_sysvar.c index f62da128e3..b9600ad710 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar.c +++ b/src/flamenco/runtime/sysvar/test_sysvar.c @@ -10,22 +10,34 @@ #include "test_sysvar_stake_history.c" #include "../../../util/fd_util.h" +__attribute__((aligned(FD_SHMEM_NORMAL_PAGE_SZ))) +static uchar wksp_mem[ 2<<20 ]; /* 2 MiB */ + int main( int argc, char ** argv ) { fd_boot( &argc, &argv ); + ulong const wksp_part_max = 16UL; + ulong const wksp_data_max = fd_wksp_data_max_est( sizeof(wksp_mem), wksp_part_max ); + fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( wksp_mem, "wksp", 1U, wksp_part_max, wksp_data_max ) ); + FD_TEST( wksp ); + fd_shmem_join_anonymous( "shmem", FD_SHMEM_JOIN_MODE_READ_WRITE, wksp, wksp_mem, FD_SHMEM_NORMAL_PAGE_SZ, sizeof(wksp_mem)/FD_SHMEM_NORMAL_PAGE_SZ ); + test_sysvar_cache(); test_sysvar_clock(); test_sysvar_epoch_rewards(); test_sysvar_epoch_schedule(); test_sysvar_last_restart_slot(); - test_sysvar_recent_hashes(); + test_sysvar_recent_hashes( wksp ); test_sysvar_rent(); test_sysvar_slot_hashes(); test_sysvar_slot_history(); - test_sysvar_stake_history(); + test_sysvar_stake_history( wksp ); + + FD_TEST( fd_shmem_leave_anonymous( wksp_mem, NULL )==0 ); + FD_TEST( fd_wksp_delete( fd_wksp_leave( wksp ) ) ); FD_LOG_NOTICE(( "pass" )); fd_halt(); diff --git a/src/flamenco/runtime/sysvar/test_sysvar_cache.c b/src/flamenco/runtime/sysvar/test_sysvar_cache.c index e325e492bc..530dd7d694 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_cache.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_cache.c @@ -1,5 +1,40 @@ +#include "fd_sysvar_cache.h" #include "fd_sysvar_cache_private.h" +#include "test_sysvar_cache_util.h" #include "../fd_system_ids.h" +#include "../context/fd_exec_slot_ctx.h" +#include + +test_sysvar_cache_env_t * +test_sysvar_cache_env_create( test_sysvar_cache_env_t * env, + fd_wksp_t * wksp ) { + memset( env, 0, sizeof(test_sysvar_cache_env_t) ); + ulong const funk_tag = 99UL; /* unique */ + ulong const wksp_tag = 98UL; /* arbitrary */ + ulong const funk_seed = 17UL; /* arbitrary */ + ulong const txn_max = 2UL; + ulong const rec_max = 32UL; + void * funk_mem = fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_footprint( txn_max, rec_max ), funk_tag ); + fd_funk_t * funk = fd_funk_join( env->funk, fd_funk_new( funk_mem, funk_tag, funk_seed, txn_max, rec_max ) ); + FD_TEST( funk ); + fd_bank_t * bank = fd_wksp_alloc_laddr( wksp, alignof(fd_bank_t), sizeof(fd_bank_t), wksp_tag ); + env->slot_ctx->magic = FD_EXEC_SLOT_CTX_MAGIC; + env->slot_ctx->bank = bank; + env->slot_ctx->funk = funk; + env->sysvar_cache = fd_sysvar_cache_join( fd_sysvar_cache_new( bank->sysvar_cache ) ); + return env; +} + +void +test_sysvar_cache_env_destroy( test_sysvar_cache_env_t * env ) { + FD_TEST( env ); + FD_TEST( fd_sysvar_cache_delete( fd_sysvar_cache_leave( env->sysvar_cache ) ) ); + fd_wksp_free_laddr( env->slot_ctx->bank ); + void * shfunk = NULL; + FD_TEST( fd_funk_leave( env->funk, &shfunk ) ); + fd_funk_delete_fast( shfunk ); + memset( env, 0, sizeof(test_sysvar_cache_env_t) ); +} static void test_sysvar_map( void ) { @@ -39,7 +74,182 @@ test_sysvar_map( void ) { } } +static fd_sysvar_cache_t sysvar_cache_[1]; + +static void +test_sysvar_cache_empty( void ) { + /* Test new */ + FD_TEST( fd_sysvar_cache_new( NULL )==NULL ); + FD_TEST( fd_sysvar_cache_new( (void *)1UL )==NULL ); /* misaligned */ + void * cache_mem = fd_sysvar_cache_new( sysvar_cache_ ); + FD_TEST( cache_mem==sysvar_cache_ ); + + /* Test join */ + FD_TEST( fd_sysvar_cache_join( NULL )==NULL ); + FD_TEST( fd_sysvar_cache_join( (void *)1UL )==NULL ); /* misaligned */ + ((fd_sysvar_cache_t *)cache_mem)->magic++; + FD_TEST( fd_sysvar_cache_join( cache_mem )==NULL ); /* bad magic */ + ((fd_sysvar_cache_t *)cache_mem)->magic--; + fd_sysvar_cache_t * cache = fd_sysvar_cache_join( cache_mem ); + FD_TEST( cache ); + + /* Test leave */ + FD_TEST( fd_sysvar_cache_leave( cache )==cache_mem ); + + /* Test join_const */ + FD_TEST( fd_sysvar_cache_join_const( NULL )==NULL ); + FD_TEST( fd_sysvar_cache_join_const( (void *)1UL )==NULL ); /* misaligned */ + ((fd_sysvar_cache_t *)cache_mem)->magic++; + FD_TEST( fd_sysvar_cache_join_const( cache_mem )==NULL ); /* bad magic */ + ((fd_sysvar_cache_t *)cache_mem)->magic--; + fd_sysvar_cache_t const * cache1 = fd_sysvar_cache_join( cache_mem ); + FD_TEST( cache ); + + /* Test is_valid */ + FD_TEST( !fd_sysvar_clock_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_epoch_rewards_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_epoch_schedule_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_last_restart_slot_is_valid( cache1 ) ); + FD_TEST( !fd_sysvar_recent_hashes_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_rent_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_slot_hashes_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_slot_history_is_valid ( cache1 ) ); + FD_TEST( !fd_sysvar_stake_history_is_valid ( cache1 ) ); + + /* Test query */ + for( ulong i=0UL; imagic++; + FD_TEST( fd_sysvar_cache_delete( cache_mem )==NULL ); /* bad magic */ + ((fd_sysvar_cache_t *)cache_mem)->magic--; + FD_TEST( fd_sysvar_cache_delete( cache_mem )==sysvar_cache_ ); +} + +/* sysvar_inject places a serialized sysvar into the sysvar cache, + bypassing the database (which does not exist for the below unit tests) */ + +static int +sysvar_inject( fd_sysvar_cache_t * cache, + ulong idx, + uchar const * data, + ulong data_sz ) { + if( FD_UNLIKELY( idx>=FD_SYSVAR_CACHE_ENTRY_CNT ) ) FD_LOG_CRIT(( "Invalid sysvar idx %lu", idx )); + fd_sysvar_desc_t * desc = &cache->desc [ idx ]; + fd_sysvar_pos_t const * pos = &fd_sysvar_pos_tbl[ idx ]; + FD_TEST( data_sz <= pos->data_max ); + fd_memcpy( (uchar *)cache+pos->data_off, data, data_sz ); + desc->data_sz = (uint)data_sz; + desc->flags = 0; + return fd_sysvar_obj_restore( cache, desc, pos, 1 ); +} + +static void +test_sysvar_cache_read( void ) { + fd_sysvar_cache_t * cache = fd_sysvar_cache_join( fd_sysvar_cache_new( sysvar_cache_ ) ); + + FD_TEST( fd_sysvar_clock_is_valid( cache )==0 ); + cache->desc[ FD_SYSVAR_clock_IDX ] = (fd_sysvar_desc_t) { + .flags = FD_SYSVAR_FLAG_VALID, + .data_sz = FD_SYSVAR_CLOCK_BINCODE_SZ + }; + + /* Restore real clock sysvar account observed on-chain */ + static uchar const data[] = { + 0xef, 0x04, 0x28, 0x15, 0x00, 0x00, 0x00, 0x00, + 0x55, 0x95, 0x7d, 0x68, 0x00, 0x00, 0x00, 0x00, + 0x35, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x3a, 0x7f, 0x68, 0x00, 0x00, 0x00, 0x00 + }; + FD_TEST( sysvar_inject( cache, FD_SYSVAR_clock_IDX, data, sizeof(data) )==0 ); + FD_TEST( fd_sysvar_clock_is_valid( cache )==1 ); + ulong copy_sz = 0x95959595UL; + uchar const * copy = fd_sysvar_cache_data_query( cache, &fd_sysvar_clock_id, ©_sz ); + FD_TEST( copy_sz==sizeof(data) && fd_memeq( data, copy, sizeof(data) ) ); + fd_sol_sysvar_clock_t clock_copy = fd_sysvar_clock_read_nofail( cache ); + FD_TEST( clock_copy.slot == 0x152804efUL ); + FD_TEST( clock_copy.epoch_start_timestamp == 0x687d9555UL ); + FD_TEST( clock_copy.epoch == 0x00000335UL ); + FD_TEST( clock_copy.leader_schedule_epoch == 0x00000336UL ); + FD_TEST( clock_copy.unix_timestamp == 0x687f3a87UL ); + + /* Restore invalid sysvar */ + static uchar const invalid[] = { 1,2,3 }; + FD_TEST( sysvar_inject( cache, FD_SYSVAR_clock_IDX, invalid, sizeof(invalid) )==EINVAL ); + FD_TEST( fd_sysvar_clock_is_valid( cache )==0 ); + + fd_sysvar_cache_delete( fd_sysvar_cache_leave( cache ) ); +} + +static void +test_sysvar_cache_modify_prepare( void ) { + fd_exec_slot_ctx_t slot_ctx = {0}; + fd_bank_t bank = {0}; + slot_ctx.bank = &bank; + FD_TEST( fd_sysvar_cache_join( fd_sysvar_cache_new( bank.sysvar_cache ) ) ); + fd_sysvar_cache_t * cache = fd_bank_sysvar_cache_modify( slot_ctx.bank ); + for( ulong i=0UL; idesc [ i ]; + void * data = (uchar *)cache + pos->data_off; + + desc->data_sz = 2U; + desc->flags = FD_SYSVAR_FLAG_VALID; + FD_TEST( fd_sysvar_cache_data_modify_prepare( &slot_ctx, key, NULL, NULL )==data ); + FD_TEST( desc->flags==FD_SYSVAR_FLAG_WRITE_LOCK ); + + desc->data_sz = 2U; + desc->flags = FD_SYSVAR_FLAG_VALID; + ulong sz = 234; + FD_TEST( fd_sysvar_cache_data_modify_prepare( &slot_ctx, key, &sz, NULL )==data ); + FD_TEST( desc->flags==FD_SYSVAR_FLAG_WRITE_LOCK ); + FD_TEST( sz==2UL ); + + desc->flags = FD_SYSVAR_FLAG_VALID; + ulong sz_max = 0; + FD_TEST( fd_sysvar_cache_data_modify_prepare( &slot_ctx, key, NULL, &sz_max )==data ); + FD_TEST( desc->flags==FD_SYSVAR_FLAG_WRITE_LOCK ); + FD_TEST( sz_max==pos->data_max ); + } +} + static void test_sysvar_cache( void ) { test_sysvar_map(); + test_sysvar_cache_empty(); + test_sysvar_cache_read(); + test_sysvar_cache_modify_prepare(); } diff --git a/src/flamenco/runtime/sysvar/test_sysvar_cache_util.h b/src/flamenco/runtime/sysvar/test_sysvar_cache_util.h new file mode 100644 index 0000000000..ea85375add --- /dev/null +++ b/src/flamenco/runtime/sysvar/test_sysvar_cache_util.h @@ -0,0 +1,38 @@ +#ifndef HEADER_fd_src_flamenco_runtime_sysvar_test_sysvar_cache_util_h +#define HEADER_fd_src_flamenco_runtime_sysvar_test_sysvar_cache_util_h + +/* test_sysvar_cache_util.h provides APIs to quickly bring up a sysvar + cache environment with an underlying database. */ + +#include "fd_sysvar_cache.h" +#include "../context/fd_exec_slot_ctx.h" +#include "../../../funk/fd_funk.h" + +struct test_sysvar_cache_env { + fd_funk_t funk[1]; + fd_funk_txn_t * funk_txn; + fd_exec_slot_ctx_t slot_ctx[1]; + fd_sysvar_cache_t * sysvar_cache; +}; + +typedef struct test_sysvar_cache_env test_sysvar_cache_env_t; + +FD_PROTOTYPES_BEGIN + +/* test_sysvar_cache_env_create allocates a tiny funk instance and + slot_ctx/bank from the given workspace. Assumes there are no other + wksp allocs with tag 99. */ + +test_sysvar_cache_env_t * +test_sysvar_cache_env_create( test_sysvar_cache_env_t * env, + fd_wksp_t * wksp ); + +/* test_sysvar_cache_env_destroy undoes all allocations done by the + function above. */ + +void +test_sysvar_cache_env_destroy( test_sysvar_cache_env_t * env ); + +FD_PROTOTYPES_END + +#endif /* HEADER_fd_src_flamenco_runtime_sysvar_test_sysvar_cache_util_h */ diff --git a/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c b/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c index d4d9657b5e..e5c330d5f6 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_epoch_schedule.c @@ -28,6 +28,14 @@ test_sysvar_epoch_schedule_bounds( void ) { FD_TEST( fd_epoch_schedule_align()==FD_SYSVAR_EPOCH_SCHEDULE_ALIGN ); } +static void +test_sysvar_epoch_schedule_edge_case( void ) { + fd_epoch_schedule_t schedule = { .slots_per_epoch=0UL }; + FD_TEST( fd_slot_to_epoch( &schedule, 0UL, NULL )==0UL ); + + FD_TEST( fd_epoch_schedule_derive( &schedule, 31UL, 31UL, 0 )==NULL ); +} + static fd_epoch_schedule_t const fd_epoch_schedule_test_vectors[] = { { .slots_per_epoch= 32, .first_normal_epoch=0, .first_normal_slot= 0 }, @@ -112,12 +120,45 @@ test_epoch_schedule( fd_epoch_schedule_t const * t ) { } } +static void +test_sysvar_epoch_schedule_testnet( void ) { + fd_epoch_schedule_t const schedule = { + .slots_per_epoch = 432000, + .leader_schedule_slot_offset = 432000, + .warmup = 1, + .first_normal_epoch = 14, + .first_normal_slot = 524256 + }; + + FD_TEST( fd_slot_to_leader_schedule_epoch( &schedule, 1UL )== 1UL ); + FD_TEST( fd_slot_to_leader_schedule_epoch( &schedule, 524256UL )==15UL ); + FD_TEST( fd_slot_to_leader_schedule_epoch( &schedule, 956255UL )==15UL ); + FD_TEST( fd_slot_to_leader_schedule_epoch( &schedule, 956256UL )==16UL ); + + ulong offset = 9UL; + FD_TEST( fd_slot_to_epoch( &schedule, 524256UL, &offset )==14UL && offset==0UL ); + FD_TEST( fd_slot_to_epoch( &schedule, 524257UL, &offset )==14UL && offset==1UL ); + for( ulong off=0UL; off<432000UL; off++ ) { + FD_TEST( fd_slot_to_epoch( &schedule, 524256UL+off, &offset )==14UL && offset==off ); + } + FD_TEST( fd_slot_to_epoch( &schedule, 956256UL, &offset )==15UL && offset==0UL ); + + FD_TEST( fd_epoch_slot0( &schedule, 0UL )== 0UL ); + FD_TEST( fd_epoch_slot0( &schedule, 1UL )== 32UL ); + FD_TEST( fd_epoch_slot0( &schedule, 14UL )==524256UL ); + FD_TEST( fd_epoch_slot0( &schedule, 15UL )==956256UL ); + + FD_TEST( fd_epoch_slot_cnt( &schedule, 14UL )==432000UL ); +} + void test_sysvar_epoch_schedule( void ) { test_sysvar_epoch_schedule_bounds(); + test_sysvar_epoch_schedule_edge_case(); for( fd_epoch_schedule_t const * vec = fd_epoch_schedule_test_vectors; vec->slots_per_epoch; vec++ ) { test_epoch_schedule_derive( vec ); test_epoch_schedule ( vec ); } + test_sysvar_epoch_schedule_testnet(); } diff --git a/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c index 5df23e4365..fd1381113e 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.c @@ -1,14 +1,128 @@ +#include "fd_sysvar_base.h" #include "fd_sysvar_recent_hashes.h" +#include "test_sysvar_cache_util.h" +#include "../fd_system_ids.h" FD_IMPORT_BINARY( example_recent_hashes, "src/flamenco/runtime/sysvar/test_sysvar_recent_hashes.bin" ); +static int +fd_mem_iszero8( uchar const * mem, + ulong sz ) { + /* FIXME ... add a fast & tested "is memzero" API */ + ulong xor = 0UL; + FD_TEST( fd_ulong_is_aligned( sz, sizeof(ulong) ) ); + for( ulong i=0UL; isysvar_cache )==0 ); + + /* Cannot create any sysvar without the rent sysvar */ + fd_rent_t const rent = { + .lamports_per_uint8_year = 3480UL, + .exemption_threshold = 2.0, + .burn_percent = 100 + }; + fd_sysvar_rent_write( env->slot_ctx, &rent ); + + /* Create an empty recent hashes sysvar */ + fd_sysvar_recent_hashes_init( env->slot_ctx ); + FD_TEST( fd_sysvar_recent_hashes_is_valid( env->sysvar_cache )==1 ); + { + ulong sz = 0UL; + uchar const * data = fd_sysvar_cache_data_query( env->sysvar_cache, &fd_sysvar_recent_block_hashes_id, &sz ); + FD_TEST( data && sz==FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + FD_TEST( FD_LOAD( ulong, data )==0UL ); /* zero blockhashes */ + FD_TEST( fd_mem_iszero8( data+8, FD_SYSVAR_RECENT_HASHES_BINCODE_SZ-8 ) ); + } + + test_sysvar_cache_env_destroy( env ); +} + +static void +test_sysvar_recent_hashes_update( fd_wksp_t * wksp ) { + test_sysvar_cache_env_t env[1]; + FD_TEST( test_sysvar_cache_env_create( env, wksp ) ); + FD_TEST( fd_sysvar_recent_hashes_is_valid( env->sysvar_cache )==0 ); + + /* Cannot create any sysvar without the rent sysvar */ + fd_rent_t const rent = { + .lamports_per_uint8_year = 3480UL, + .exemption_threshold = 2.0, + .burn_percent = 100 + }; + fd_sysvar_rent_write( env->slot_ctx, &rent ); + + /* The recent blockhashes sysvar is tied to the blockhash queue */ + fd_blockhashes_t * blockhashes = fd_blockhashes_init( fd_bank_block_hash_queue_modify( env->slot_ctx->bank ), 0UL ); + FD_TEST( blockhashes ); + + /* Register a new blockhash (creating the sysvar) */ + FD_TEST( fd_sysvar_recent_hashes_is_valid( env->sysvar_cache )==0 ); + fd_hash_t poh = { .ul={ 0x110b8a330ecf93c2UL, 0xb709306fbd53c744, 0xda66f7127781dd72, 0UL } }; + fd_bank_poh_set( env->slot_ctx->bank, poh ); + fd_bank_lamports_per_signature_set( env->slot_ctx->bank, 1000UL ); + fd_sysvar_recent_hashes_update( env->slot_ctx ); + FD_TEST( fd_sysvar_recent_hashes_is_valid( env->sysvar_cache )==1 ); + { + ulong sz = 0UL; + uchar const * data = fd_sysvar_cache_data_query( env->sysvar_cache, &fd_sysvar_recent_block_hashes_id, &sz ); + FD_TEST( data && sz==FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + FD_TEST( FD_LOAD( ulong, data )==1UL ); + FD_TEST( fd_hash_eq1( FD_LOAD( fd_hash_t, data+8 ), poh ) ); + FD_TEST( FD_LOAD( ulong, data+40 )==1000UL ); /* fee calculator */ + FD_TEST( fd_mem_iszero8( data+48, FD_SYSVAR_RECENT_HASHES_BINCODE_SZ-48 ) ); + } + + /* Keep adding hashes */ + for( ulong i=0UL; i<149UL; i++ ) { + poh.ul[3] = i+1UL; + fd_bank_poh_set( env->slot_ctx->bank, poh ); + fd_bank_lamports_per_signature_set( env->slot_ctx->bank, 1001UL+i ); + fd_sysvar_recent_hashes_update( env->slot_ctx ); + + ulong sz = 0UL; + uchar const * data = fd_sysvar_cache_data_query( env->sysvar_cache, &fd_sysvar_recent_block_hashes_id, &sz ); + FD_TEST( data && sz==FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + FD_TEST( FD_LOAD( ulong, data )==i+2 ); /* count */ + } + + /* Verify queue content */ + { + ulong sz = 0UL; + uchar const * data = fd_sysvar_cache_data_query( env->sysvar_cache, &fd_sysvar_recent_block_hashes_id, &sz ); + FD_TEST( data && sz==FD_SYSVAR_RECENT_HASHES_BINCODE_SZ ); + FD_TEST( FD_LOAD( ulong, data )==150 ); /* count */ + for( ulong i=0UL; i<150UL; i++ ) { + uchar const * entry = data+8 + i*40; + fd_hash_t const hash = FD_LOAD( fd_hash_t, entry ); + ulong const lps = FD_LOAD( ulong, entry+32 ); + ulong const idx = 149UL-i; + FD_TEST( hash.ul[3]==idx ); + FD_TEST( lps ==1000UL+idx ); + + fd_blockhash_info_t * info = fd_blockhash_deq_peek_index( blockhashes->d.deque, idx ); + FD_TEST( lps==info->fee_calculator.lamports_per_signature ); + FD_TEST( fd_hash_eq1( hash, info->hash ) ); + FD_TEST( fd_blockhashes_check_age( blockhashes, &hash, i )==1 ); + } + } + + test_sysvar_cache_env_destroy( env ); +} + +static void +test_sysvar_recent_hashes( fd_wksp_t * wksp ) { test_sysvar_recent_hashes_bounds(); - /* FIXME more tests here ... */ + test_sysvar_recent_hashes_init( wksp ); + test_sysvar_recent_hashes_update( wksp ); } diff --git a/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c b/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c index 5224bad777..842e346932 100644 --- a/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c +++ b/src/flamenco/runtime/sysvar/test_sysvar_stake_history.c @@ -1,5 +1,7 @@ #include "fd_sysvar_stake_history.h" #include "../../types/fd_types.h" +#include "test_sysvar_cache_util.h" +#include "../fd_system_ids.h" FD_IMPORT_BINARY( example_stake_history, "src/flamenco/runtime/sysvar/test_sysvar_stake_history.bin" ); @@ -17,7 +19,58 @@ test_sysvar_stake_history_bounds( void ) { } static void -test_sysvar_stake_history( void ) { +test_sysvar_stake_history_update( fd_wksp_t * wksp ) { + test_sysvar_cache_env_t env[1]; + FD_TEST( test_sysvar_cache_env_create( env, wksp ) ); + FD_TEST( fd_sysvar_stake_history_is_valid( env->sysvar_cache )==0 ); + + /* Cannot create any sysvar without the rent sysvar */ + fd_rent_t const rent = { + .lamports_per_uint8_year = 3480UL, + .exemption_threshold = 2.0, + .burn_percent = 100 + }; + fd_sysvar_rent_write( env->slot_ctx, &rent ); + + /* Stake History update requires epoch schedule */ + fd_epoch_schedule_t const schedule = { + .slots_per_epoch = 432000, + .leader_schedule_slot_offset = 432000, + .warmup = 0, + .first_normal_epoch = 0, + .first_normal_slot = 0 + }; + fd_sysvar_epoch_schedule_write( env->slot_ctx, &schedule ); + + /* Update should be a no-op if not at the epoch boundary */ + env->slot_ctx->bank->slot_ = 3; + fd_bank_parent_slot_set( env->slot_ctx->bank, 2 ); + fd_epoch_stake_history_entry_pair_t const entry0 = { + .epoch = 1UL, .entry = { + .effective = 0x111UL, + .activating = 0x222UL, + .deactivating = 0x333UL, + } + }; + fd_sysvar_stake_history_update( env->slot_ctx, &entry0 ); + FD_TEST( fd_sysvar_stake_history_is_valid( env->sysvar_cache )==0 ); + + env->slot_ctx->bank->slot_ = 432000; + fd_bank_parent_slot_set( env->slot_ctx->bank, 431999 ); + fd_sysvar_stake_history_update( env->slot_ctx, &entry0 ); + FD_TEST( fd_sysvar_stake_history_is_valid( env->sysvar_cache )==1 ); + + { + ulong sz = 0UL; + uchar const * data = fd_sysvar_cache_data_query( env->sysvar_cache, &fd_sysvar_stake_history_id, &sz ); + FD_TEST( data && sz==FD_SYSVAR_STAKE_HISTORY_BINCODE_SZ ); + } + + test_sysvar_cache_env_destroy( env ); +} + +static void +test_sysvar_stake_history( fd_wksp_t * wksp ) { test_sysvar_stake_history_bounds(); - /* FIXME more tests here ... */ + test_sysvar_stake_history_update( wksp ); } diff --git a/src/flamenco/types/fd_types_custom.h b/src/flamenco/types/fd_types_custom.h index db8bf40b35..67df334740 100644 --- a/src/flamenco/types/fd_types_custom.h +++ b/src/flamenco/types/fd_types_custom.h @@ -34,6 +34,14 @@ fd_hash_eq( fd_hash_t const * a, return 0==memcmp( a, b, sizeof(fd_hash_t) ); } +FD_FN_PURE static inline int +fd_hash_eq1( fd_hash_t a, + fd_hash_t b ) { + return + ( a.ul[0]==b.ul[0] ) & ( a.ul[1]==b.ul[1] ) & + ( a.ul[2]==b.ul[2] ) & ( a.ul[3]==b.ul[3] ); +} + union fd_signature { uchar uc[ 64 ]; ulong ul[ 8 ];