From 4a8027f125fed3e7f61e093629608d53672dc895 Mon Sep 17 00:00:00 2001 From: Manik Jain Date: Wed, 4 Dec 2024 19:51:20 +0000 Subject: [PATCH] flamenco: use `new_rate_activation_epoch` properly in epoch calculations --- src/flamenco/rewards/fd_rewards.c | 35 ++++++++++++++----- src/flamenco/runtime/fd_runtime.c | 12 +++++-- .../runtime/program/fd_stake_program.c | 28 ++++++++------- .../runtime/program/fd_stake_program.h | 5 +++ .../runtime/tests/run_ledger_tests_all.txt | 1 + src/flamenco/stakes/fd_stakes.c | 8 ++--- src/flamenco/stakes/fd_stakes.h | 6 ++-- 7 files changed, 67 insertions(+), 28 deletions(-) diff --git a/src/flamenco/rewards/fd_rewards.c b/src/flamenco/rewards/fd_rewards.c index 18c069a868..f9f4edf24e 100644 --- a/src/flamenco/rewards/fd_rewards.c +++ b/src/flamenco/rewards/fd_rewards.c @@ -104,10 +104,11 @@ slot_in_year_for_inflation( fd_exec_slot_ctx_t * slot_ctx ) { https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/programs/stake/src/points.rs#L109 */ static void -calculate_stake_points_and_credits ( +calculate_stake_points_and_credits( fd_stake_history_t const * stake_history, fd_stake_t * stake, fd_vote_state_versioned_t * vote_state_versioned, + ulong * new_rate_activation_epoch, fd_calculated_stake_points_t * result ) { @@ -173,7 +174,7 @@ calculate_stake_points_and_credits ( new_credits_observed = fd_ulong_max( new_credits_observed, final_epoch_credits ); - ulong stake_amount = fd_stake_activating_and_deactivating( &stake->delegation, ele->epoch, stake_history, NULL ).effective; + ulong stake_amount = fd_stake_activating_and_deactivating( &stake->delegation, ele->epoch, stake_history, new_rate_activation_epoch ).effective; points += (uint128)stake_amount * earned_credits; } @@ -191,10 +192,11 @@ calculate_stake_rewards( fd_vote_state_versioned_t * vote_state_versioned, ulong rewarded_epoch, fd_point_value_t * point_value, + ulong * new_rate_activation_epoch, fd_calculated_stake_rewards_t * result ) { fd_calculated_stake_points_t stake_points_result = {0}; - calculate_stake_points_and_credits( stake_history, &stake_state->inner.stake.stake, vote_state_versioned, &stake_points_result); + calculate_stake_points_and_credits( stake_history, &stake_state->inner.stake.stake, vote_state_versioned, new_rate_activation_epoch, &stake_points_result); // Drive credits_observed forward unconditionally when rewards are disabled // or when this is the stake's activation epoch @@ -238,9 +240,10 @@ redeem_rewards( fd_stake_history_t const * stake_history, fd_vote_state_versioned_t * vote_state_versioned, ulong rewarded_epoch, fd_point_value_t * point_value, + ulong * new_rate_activation_epoch, fd_calculated_stake_rewards_t * calculated_stake_rewards) { - int rc = calculate_stake_rewards( stake_history, stake_state, vote_state_versioned, rewarded_epoch, point_value, calculated_stake_rewards ); + int rc = calculate_stake_rewards( stake_history, stake_state, vote_state_versioned, rewarded_epoch, point_value, new_rate_activation_epoch, calculated_stake_rewards ); if ( FD_UNLIKELY( rc != 0 ) ) { return rc; } @@ -254,6 +257,7 @@ calculate_points( fd_stake_state_v2_t * stake_state, fd_vote_state_versioned_t * vote_state_versioned, fd_stake_history_t const * stake_history, + ulong * new_rate_activation_epoch, uint128 * result ) { if ( FD_UNLIKELY( !fd_stake_state_v2_is_stake( stake_state ) ) ) { @@ -261,7 +265,7 @@ calculate_points( } fd_calculated_stake_points_t stake_point_result; - calculate_stake_points_and_credits( stake_history, &stake_state->inner.stake.stake, vote_state_versioned, &stake_point_result ); + calculate_stake_points_and_credits( stake_history, &stake_state->inner.stake.stake, vote_state_versioned, new_rate_activation_epoch, &stake_point_result ); *result = stake_point_result.points; return FD_EXECUTOR_INSTR_SUCCESS; @@ -341,6 +345,13 @@ calculate_reward_points_partitioned( ulong minimum_stake_delegation = get_minimum_stake_delegation( slot_ctx ); /* Calculate the points for each stake delegation */ + int _err[1]; + ulong * new_warmup_cooldown_rate_epoch = fd_scratch_alloc( alignof(ulong), sizeof(ulong) ); + int is_some = fd_new_warmup_cooldown_rate_epoch( slot_ctx, new_warmup_cooldown_rate_epoch, _err ); + if( FD_UNLIKELY( !is_some ) ) { + new_warmup_cooldown_rate_epoch = NULL; + } + for( fd_delegation_pair_t_mapnode_t const * n = fd_delegation_pair_t_map_minimum_const( epoch_bank->stakes.stake_delegations_pool, epoch_bank->stakes.stake_delegations_root ); n; n = fd_delegation_pair_t_map_successor_const( epoch_bank->stakes.stake_delegations_pool, n ) @@ -413,7 +424,7 @@ calculate_reward_points_partitioned( } uint128 account_points; - err = calculate_points( stake_state, vote_state, stake_history, &account_points ); + err = calculate_points( stake_state, vote_state, stake_history, new_warmup_cooldown_rate_epoch, &account_points ); if ( FD_UNLIKELY( err ) ) { FD_LOG_DEBUG(( "failed to calculate points" )); continue; @@ -497,7 +508,7 @@ calculate_reward_points_partitioned( } uint128 account_points; - err = calculate_points( stake_state, vote_state, stake_history, &account_points ); + err = calculate_points( stake_state, vote_state, stake_history, new_warmup_cooldown_rate_epoch, &account_points ); if ( FD_UNLIKELY( err ) ) { FD_LOG_DEBUG(( "failed to calculate points" )); continue; @@ -524,6 +535,12 @@ calculate_stake_vote_rewards_account( fd_calculate_stake_vote_rewards_result_t * result ) { FD_SCRATCH_SCOPE_BEGIN { + int _err[1]; + ulong * new_warmup_cooldown_rate_epoch = fd_scratch_alloc( alignof(ulong), sizeof(ulong) ); + int is_some = fd_new_warmup_cooldown_rate_epoch( slot_ctx, new_warmup_cooldown_rate_epoch, _err ); + if( FD_UNLIKELY( !is_some ) ) { + new_warmup_cooldown_rate_epoch = NULL; + } fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); ulong minimum_stake_delegation = get_minimum_stake_delegation( slot_ctx ); @@ -578,7 +595,7 @@ calculate_stake_vote_rewards_account( /* Note, this doesn't actually redeem any rewards.. this is a misnomer. */ fd_calculated_stake_rewards_t calculated_stake_rewards[1] = {0}; - int err = redeem_rewards( stake_history, stake_state, vote_state_versioned, rewarded_epoch, point_value, calculated_stake_rewards ); + int err = redeem_rewards( stake_history, stake_state, vote_state_versioned, rewarded_epoch, point_value, new_warmup_cooldown_rate_epoch, calculated_stake_rewards ); if ( err != 0) { FD_LOG_DEBUG(( "redeem_rewards failed for %s with error %d", FD_BASE58_ENC_32_ALLOCA( stake_acc->key ), err )); return; @@ -1114,6 +1131,7 @@ fd_begin_partitioned_rewards( const fd_hash_t * parent_blockhash, ulong parent_epoch ) { +FD_SCRATCH_SCOPE_BEGIN { /* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L55 */ fd_calculate_rewards_and_distribute_vote_rewards_result_t rewards_result[1] = {0}; calculate_rewards_and_distribute_vote_rewards( @@ -1141,6 +1159,7 @@ fd_begin_partitioned_rewards( rewards_result->point_value, parent_blockhash ); +} FD_SCRATCH_SCOPE_END; } /* diff --git a/src/flamenco/runtime/fd_runtime.c b/src/flamenco/runtime/fd_runtime.c index aa6a963e4b..dae7023de3 100644 --- a/src/flamenco/runtime/fd_runtime.c +++ b/src/flamenco/runtime/fd_runtime.c @@ -4534,8 +4534,16 @@ void fd_process_new_epoch( else if (FD_FEATURE_ACTIVE(slot_ctx, update_hashes_per_tick2)) epoch_bank->hashes_per_tick = UPDATED_HASHES_PER_TICK2; + /* Get the new rate activation epoch */ + int _err[1]; + ulong * new_rate_activation_epoch = fd_scratch_alloc( alignof(ulong), sizeof(ulong) ); + int is_some = fd_new_warmup_cooldown_rate_epoch( slot_ctx, new_rate_activation_epoch, _err ); + if( FD_UNLIKELY( !is_some ) ) { + new_rate_activation_epoch = NULL; + } + /* Updates stake history sysvar accumulated values. */ - fd_stakes_activate_epoch( slot_ctx ); + fd_stakes_activate_epoch( slot_ctx, new_rate_activation_epoch ); /* Update the stakes epoch value to the new epoch */ epoch_bank->stakes.epoch = epoch; @@ -4560,7 +4568,7 @@ void fd_process_new_epoch( fd_stake_history_t const * history = fd_sysvar_cache_stake_history( slot_ctx->sysvar_cache ); if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "StakeHistory sysvar is missing from sysvar cache" )); - refresh_vote_accounts( slot_ctx, history ); + refresh_vote_accounts( slot_ctx, history, new_rate_activation_epoch ); fd_update_stake_delegations( slot_ctx ); /* Replace stakes at T-2 (slot_ctx->slot_bank.epoch_stakes) by stakes at T-1 (epoch_bank->next_epoch_stakes) */ diff --git a/src/flamenco/runtime/program/fd_stake_program.c b/src/flamenco/runtime/program/fd_stake_program.c index aee1049c7a..c3ea761272 100644 --- a/src/flamenco/runtime/program/fd_stake_program.c +++ b/src/flamenco/runtime/program/fd_stake_program.c @@ -715,20 +715,24 @@ 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 -static inline int -new_warmup_cooldown_rate_epoch( fd_exec_instr_ctx_t const * invoke_context, - /* out */ ulong * epoch, - int * err ) { +int +fd_new_warmup_cooldown_rate_epoch( fd_exec_slot_ctx_t const * slot_ctx, + /* out */ ulong * epoch, + int * err ) { *err = 0; - fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_cache_epoch_schedule( invoke_context->slot_ctx->sysvar_cache ); + fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_cache_epoch_schedule( slot_ctx->sysvar_cache ); if( FD_UNLIKELY( !epoch_schedule ) ) { *epoch = ULONG_MAX; *err = FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; return 1; } - ulong slot = invoke_context->epoch_ctx->features.reduce_stake_warmup_cooldown; - *epoch = fd_slot_to_epoch( epoch_schedule, slot, NULL ); - 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_ctx, reduce_stake_warmup_cooldown ) ) ) { + ulong slot = slot_ctx->epoch_ctx->features.reduce_stake_warmup_cooldown; + *epoch = fd_slot_to_epoch( epoch_schedule, slot, NULL ); + return 1; + } + return 0; } /**********************************************************************/ @@ -793,7 +797,7 @@ get_if_mergeable( fd_exec_instr_ctx_t * invoke_context, // not const to 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 = new_warmup_cooldown_rate_epoch( invoke_context, &new_rate_activation_epoch, &err ); + int is_some = fd_new_warmup_cooldown_rate_epoch( invoke_context->slot_ctx, &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 @@ -1102,7 +1106,7 @@ get_stake_status( fd_exec_instr_ctx_t const * invoke_context, return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR; ulong new_rate_activation_epoch = ULONG_MAX; int err; - int is_some = new_warmup_cooldown_rate_epoch( invoke_context, &new_rate_activation_epoch, &err ); + int is_some = fd_new_warmup_cooldown_rate_epoch( invoke_context->slot_ctx, &new_rate_activation_epoch, &err ); if( FD_UNLIKELY( err ) ) return err; *out = @@ -1137,7 +1141,7 @@ redelegate_stake( fd_exec_instr_ctx_t const * ctx, uint * custom_err ) { ulong new_rate_activation_epoch = ULONG_MAX; int err; - int is_some = new_warmup_cooldown_rate_epoch( ctx, &new_rate_activation_epoch, &err ); + int is_some = fd_new_warmup_cooldown_rate_epoch( ctx->slot_ctx, &new_rate_activation_epoch, &err ); if( FD_UNLIKELY( err ) ) return err; // FIXME FD_LIKELY @@ -2734,7 +2738,7 @@ 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 = new_warmup_cooldown_rate_epoch( ctx, &new_rate_activation_epoch, &err ); + int is_some = fd_new_warmup_cooldown_rate_epoch( ctx->slot_ctx, &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 diff --git a/src/flamenco/runtime/program/fd_stake_program.h b/src/flamenco/runtime/program/fd_stake_program.h index 13f03721fe..22008427c6 100644 --- a/src/flamenco/runtime/program/fd_stake_program.h +++ b/src/flamenco/runtime/program/fd_stake_program.h @@ -15,6 +15,11 @@ FD_PROTOTYPES_BEGIN +int +fd_new_warmup_cooldown_rate_epoch( fd_exec_slot_ctx_t const * slot_ctx, + /* out */ ulong * 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 a stake account may have been modified. */ diff --git a/src/flamenco/runtime/tests/run_ledger_tests_all.txt b/src/flamenco/runtime/tests/run_ledger_tests_all.txt index 9e859687de..e9a8cb6c04 100644 --- a/src/flamenco/runtime/tests/run_ledger_tests_all.txt +++ b/src/flamenco/runtime/tests/run_ledger_tests_all.txt @@ -74,3 +74,4 @@ src/flamenco/runtime/tests/run_ledger_test.sh -l mainnet-301359740 -s snapshot-3 src/flamenco/runtime/tests/run_ledger_test.sh -l testnet-302734641 -s snapshot-302734640-9e44jEVavfHC253DSBGSjTFt2diZrgcMHTRZtpUvisvr.tar.zst -p 50 -y 16 -m 5000000 -e 302734658 -c 2.0.10 src/flamenco/runtime/tests/run_ledger_test.sh -l migrate-feature-program -s snapshot-500-Cz6iotFK7kNcGTpyUZeX4CHbT2uff2uzVW8RXXysBnVk.tar.zst -p 50 -y 16 -m 5000000 -e 675 -c 2.1.0 -o 4eohviozzEeivk1y9UbrnekbAFMDQyJz5JjA9Y6gyvky src/flamenco/runtime/tests/run_ledger_test.sh -l migrate-config-program -s snapshot-500-HCg5AHVPC6JAqZo4p6iMcDmo586ZjkxxPpxfAwCHqroy.tar.zst -p 50 -y 16 -m 5000000 -e 675 -c 2.1.0 -o 2Fr57nzzkLYXW695UdDxDeR5fhnZWSttZeZYemrnpGFV +src/flamenco/runtime/tests/run_ledger_test.sh -l per-stake-history-new-rate-activation-epoch -s snapshot-50-47DbuHpi6gXmZKQ1FUSAAfkgnuWrkfTAtx3Hk5Gqsu5W.tar.zst -p 50 -y 16 -m 5000000 -e 675 -c 2.1.0 diff --git a/src/flamenco/stakes/fd_stakes.c b/src/flamenco/stakes/fd_stakes.c index 55cac592e8..0d8f66c4ad 100644 --- a/src/flamenco/stakes/fd_stakes.c +++ b/src/flamenco/stakes/fd_stakes.c @@ -160,7 +160,8 @@ stake account. https://github.com/solana-labs/solana/blob/c091fd3da8014c0ef83b626318018f238f506435/runtime/src/stakes.rs#L562 */ void refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, - fd_stake_history_t const * history ) { + fd_stake_history_t const * history, + ulong * new_rate_activation_epoch ) { fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); fd_stakes_t * stakes = &epoch_bank->stakes; @@ -171,7 +172,6 @@ refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, void * mem = fd_scratch_alloc( fd_stake_weight_t_map_align(), fd_stake_weight_t_map_footprint(maplen)); fd_stake_weight_t_mapnode_t * pool = fd_stake_weight_t_map_join(fd_stake_weight_t_map_new(mem, maplen)); fd_stake_weight_t_mapnode_t * root = NULL; - ulong * new_rate_activation_epoch = NULL; // Iterate over each stake delegation and accumulate the stake amount associated with the given vote account. for ( @@ -276,7 +276,8 @@ refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, /* https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/runtime/src/stakes.rs#L169 */ void -fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx) { +fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, + ulong * new_rate_activation_epoch ) { fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); fd_stakes_t * stakes = &epoch_bank->stakes; @@ -298,7 +299,6 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx) { fd_stake_weight_t_mapnode_t * pool = fd_stake_weight_t_map_alloc(slot_ctx->valloc, 10000); fd_stake_weight_t_mapnode_t * root = NULL; - ulong * new_rate_activation_epoch = NULL; for ( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum(stakes->stake_delegations_pool, stakes->stake_delegations_root); n; n = fd_delegation_pair_t_map_successor(stakes->stake_delegations_pool, n) ) { FD_BORROWED_ACCOUNT_DECL(acc); int rc = fd_acc_mgr_view(slot_ctx->acc_mgr, slot_ctx->funk_txn, &n->elem.account, acc); diff --git a/src/flamenco/stakes/fd_stakes.h b/src/flamenco/stakes/fd_stakes.h index 0113db2f4f..88b4a2eb68 100644 --- a/src/flamenco/stakes/fd_stakes.h +++ b/src/flamenco/stakes/fd_stakes.h @@ -29,7 +29,8 @@ fd_stake_weights_by_node( fd_vote_accounts_t const * accs, void -fd_stakes_activate_epoch( fd_exec_slot_ctx_t * global ); +fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, + ulong * new_rate_activation_epoch ); fd_stake_history_entry_t stake_and_activating( fd_delegation_t const * delegation, ulong target_epoch, fd_stake_history_t * stake_history, ulong * new_rate_activation_epoch ); @@ -47,7 +48,8 @@ fd_stakes_upsert_stake_delegation( fd_exec_slot_ctx_t * slot_ctx, fd_borrowed_ac void refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, - fd_stake_history_t const * history ); + fd_stake_history_t const * history, + ulong * new_rate_activation_epoch ); FD_PROTOTYPES_END