Skip to content

Commit

Permalink
epoch_opt: First pass at optimizing the epoch boundry
Browse files Browse the repository at this point in the history
  • Loading branch information
jumpsiegel committed Dec 19, 2024
1 parent 75d7984 commit 4617bd4
Show file tree
Hide file tree
Showing 17 changed files with 752 additions and 651 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,6 @@ dump/test-vectors/instr/fixtures/stake/cbdeebc6c636bf1d.bin.fix
dump/test-vectors/instr/fixtures/stake/cc473d1945c5f84d.bin.fix
dump/test-vectors/instr/fixtures/stake/ccf84d344fa13569.bin.fix
dump/test-vectors/instr/fixtures/stake/ccfcbaa439162210.bin.fix
dump/test-vectors/instr/fixtures/stake/cd308a27e93b46140f6ee2ade4ef6006257949d4.fix
dump/test-vectors/instr/fixtures/stake/cd6d46e202da90e8.bin.fix
dump/test-vectors/instr/fixtures/stake/cdb260e64302d072.bin.fix
dump/test-vectors/instr/fixtures/stake/ce2f906d04cd5868.bin.fix
Expand Down
173 changes: 33 additions & 140 deletions src/flamenco/rewards/fd_rewards.c
Original file line number Diff line number Diff line change
Expand Up @@ -254,18 +254,14 @@ redeem_rewards( fd_stake_history_t const * stake_history,
/* https://github.com/anza-xyz/agave/blob/cbc8320d35358da14d79ebcada4dfb6756ffac79/programs/stake/src/points.rs#L70 */
static int
calculate_points(
fd_stake_state_v2_t * stake_state,
fd_stake_t * stake,
fd_vote_state_versioned_t * vote_state_versioned,
fd_stake_history_t const * stake_history,
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 ) ) ) {
return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
}

fd_calculated_stake_points_t 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 );
calculate_stake_points_and_credits( stake_history, stake, vote_state_versioned, new_rate_activation_epoch, &stake_point_result );
*result = stake_point_result.points;

return FD_EXECUTOR_INSTR_SUCCESS;
Expand Down Expand Up @@ -334,14 +330,13 @@ calculate_reward_points_partitioned(
fd_exec_slot_ctx_t * slot_ctx,
fd_stake_history_t const * stake_history,
ulong rewards,
fd_point_value_t * result
fd_point_value_t * result,
fd_epoch_info_t *temp_info
) {
/* There is a cache of vote account keys stored in the slot context */
/* TODO: check this cache is correct */

uint128 points = 0;
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 );

/* Calculate the points for each stake delegation */
Expand All @@ -352,128 +347,18 @@ calculate_reward_points_partitioned(
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 )
) {
FD_SCRATCH_SCOPE_BEGIN {
fd_valloc_t valloc = fd_scratch_virtual();

/* Fetch the stake account */
FD_BORROWED_ACCOUNT_DECL(stake_acc_rec);
fd_pubkey_t const * stake_acc = &n->elem.account;
int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, stake_acc, stake_acc_rec);
if ( err != FD_ACC_MGR_SUCCESS && err != FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
FD_LOG_ERR(( "failed to read stake account from funk" ));
continue;
}
if ( err == FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
FD_LOG_DEBUG(( "stake account not found %s", FD_BASE58_ENC_32_ALLOCA( stake_acc->uc ) ));
continue;
}
if ( stake_acc_rec->const_meta->info.lamports == 0 ) {
FD_LOG_DEBUG(( "stake acc with zero lamports %s", FD_BASE58_ENC_32_ALLOCA( stake_acc->uc ) ));
continue;
}

/* Check the minimum stake delegation */
fd_stake_state_v2_t stake_state[1] = {0};
err = fd_stake_get_state( stake_acc_rec, &valloc, stake_state );
if ( err != 0 ) {
FD_LOG_DEBUG(( "get stake state failed" ));
continue;
}
if ( FD_UNLIKELY( stake_state->inner.stake.stake.delegation.stake < minimum_stake_delegation ) ) {
continue;
}

/* Check that the vote account is present in our cache */
fd_vote_accounts_pair_t_mapnode_t key;
fd_pubkey_t const * voter_acc = &n->elem.delegation.voter_pubkey;
fd_memcpy( &key.elem.key, voter_acc, sizeof(fd_pubkey_t) );
fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank(
slot_ctx->epoch_ctx );
if ( FD_UNLIKELY( fd_vote_accounts_pair_t_map_find(
epoch_bank->stakes.vote_accounts.vote_accounts_pool,
epoch_bank->stakes.vote_accounts.vote_accounts_root,
&key ) == NULL ) ) {
FD_LOG_DEBUG(( "vote account missing from cache" ));
continue;
}

/* Check that the vote account is valid and has the correct owner */
FD_BORROWED_ACCOUNT_DECL(voter_acc_rec);
err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, voter_acc, voter_acc_rec );
if ( FD_UNLIKELY( err ) ) {
FD_LOG_DEBUG(( "failed to read vote account from funk" ));
continue;
}
if( FD_UNLIKELY( memcmp( &voter_acc_rec->const_meta->info.owner, fd_solana_vote_program_id.key, sizeof(fd_pubkey_t) ) != 0 ) ) {
FD_LOG_DEBUG(( "vote account has wrong owner" ));
continue;
}
fd_bincode_decode_ctx_t decode = {
.data = voter_acc_rec->const_data,
.dataend = voter_acc_rec->const_data + voter_acc_rec->const_meta->dlen,
.valloc = valloc,
};
fd_vote_state_versioned_t vote_state[1] = {0};
if( FD_UNLIKELY( 0!=fd_vote_state_versioned_decode( vote_state, &decode ) ) ) {
FD_LOG_DEBUG(( "vote_state_versioned_decode failed" ));
continue;
}

uint128 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;
}

points += account_points;
} FD_SCRATCH_SCOPE_END;
}

/* TODO: factor this out */
/* Calculate points for each stake account in slot_bank.stake_account_keys.stake_accounts_pool */
for ( fd_stake_accounts_pair_t_mapnode_t const * n = fd_stake_accounts_pair_t_map_minimum_const( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root );
n;
n = fd_stake_accounts_pair_t_map_successor_const( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, n ) ) {

for ( ulong idx = 0; idx < temp_info->infos_len; idx++ ) {
FD_SCRATCH_SCOPE_BEGIN {
fd_valloc_t valloc = fd_scratch_virtual();
fd_stake_t * stake = &temp_info->infos[idx].stake;

/* Fetch the stake account */
FD_BORROWED_ACCOUNT_DECL(stake_acc_rec);
fd_pubkey_t const * stake_acc = &n->elem.key;
int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, stake_acc, stake_acc_rec);
if ( err != FD_ACC_MGR_SUCCESS && err != FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
FD_LOG_ERR(( "failed to read stake account from funk" ));
continue;
}
if ( err == FD_ACC_MGR_ERR_UNKNOWN_ACCOUNT ) {
FD_LOG_DEBUG(( "stake account not found %s", FD_BASE58_ENC_32_ALLOCA( stake_acc->uc ) ));
continue;
}
if ( stake_acc_rec->const_meta->info.lamports == 0 ) {
FD_LOG_DEBUG(( "stake acc with zero lamports %s", FD_BASE58_ENC_32_ALLOCA( stake_acc->uc ) ));
continue;
}

/* Check the minimum stake delegation */
fd_stake_state_v2_t stake_state[1] = {0};
err = fd_stake_get_state( stake_acc_rec, &valloc, stake_state );
if ( err != 0 ) {
FD_LOG_DEBUG(( "get stake state failed" ));
continue;
}
if ( FD_UNLIKELY( stake_state->inner.stake.stake.delegation.stake < minimum_stake_delegation ) ) {
if ( FD_UNLIKELY( stake->delegation.stake < minimum_stake_delegation ) ) {
continue;
}

/* Check that the vote account is present in our cache */
fd_vote_accounts_pair_t_mapnode_t key;
fd_pubkey_t const * voter_acc = &stake_state->inner.stake.stake.delegation.voter_pubkey;
fd_pubkey_t const * voter_acc = &stake->delegation.voter_pubkey;
fd_memcpy( &key.elem.key, voter_acc, sizeof(fd_pubkey_t) );
fd_epoch_bank_t const * epoch_bank = fd_exec_epoch_ctx_epoch_bank(
slot_ctx->epoch_ctx );
Expand All @@ -486,8 +371,9 @@ calculate_reward_points_partitioned(
}

/* Check that the vote account is valid and has the correct owner */
// TODO: we need to cache this away...
FD_BORROWED_ACCOUNT_DECL(voter_acc_rec);
err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, voter_acc, voter_acc_rec );
int err = fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, voter_acc, voter_acc_rec );
if ( FD_UNLIKELY( err ) ) {
FD_LOG_DEBUG(( "failed to read vote account from funk" ));
continue;
Expand All @@ -508,7 +394,7 @@ calculate_reward_points_partitioned(
}

uint128 account_points;
err = calculate_points( stake_state, vote_state, stake_history, new_warmup_cooldown_rate_epoch, &account_points );
err = calculate_points( stake, vote_state, stake_history, new_warmup_cooldown_rate_epoch, &account_points );
if ( FD_UNLIKELY( err ) ) {
FD_LOG_DEBUG(( "failed to calculate points" ));
continue;
Expand Down Expand Up @@ -741,7 +627,8 @@ calculate_validator_rewards(
fd_exec_slot_ctx_t * slot_ctx,
ulong rewarded_epoch,
ulong rewards,
fd_calculate_validator_rewards_result_t * result
fd_calculate_validator_rewards_result_t * result,
fd_epoch_info_t *temp_info
) {
/* https://github.com/firedancer-io/solana/blob/dab3da8e7b667d7527565bddbdbecf7ec1fb868e/runtime/src/bank.rs#L2759-L2786 */
fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history( slot_ctx->sysvar_cache );
Expand All @@ -750,7 +637,7 @@ calculate_validator_rewards(
}

/* Calculate the epoch reward points from stake/vote accounts */
calculate_reward_points_partitioned( slot_ctx, stake_history, rewards, &result->point_value );
calculate_reward_points_partitioned( slot_ctx, stake_history, rewards, &result->point_value, temp_info );

/* Calculate the stake and vote rewards for each account */
calculate_stake_vote_rewards(
Expand Down Expand Up @@ -853,10 +740,11 @@ hash_rewards_into_partitions(
https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L214 */
static void
calculate_rewards_for_partitioning(
fd_exec_slot_ctx_t * slot_ctx,
fd_exec_slot_ctx_t * slot_ctx,
ulong prev_epoch,
const fd_hash_t * parent_blockhash,
fd_partitioned_rewards_calculation_t * result
const fd_hash_t * parent_blockhash,
fd_partitioned_rewards_calculation_t * result,
fd_epoch_info_t * temp_info
) {
/* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L227 */
fd_prev_epoch_inflation_rewards_t rewards;
Expand All @@ -865,7 +753,7 @@ calculate_rewards_for_partitioning(
fd_slot_bank_t const * slot_bank = &slot_ctx->slot_bank;

fd_calculate_validator_rewards_result_t validator_result[1] = {0};
calculate_validator_rewards( slot_ctx, prev_epoch, rewards.validator_rewards, validator_result );
calculate_validator_rewards( slot_ctx, prev_epoch, rewards.validator_rewards, validator_result, temp_info );

hash_rewards_into_partitions(
slot_ctx,
Expand Down Expand Up @@ -893,11 +781,12 @@ calculate_rewards_and_distribute_vote_rewards(
fd_exec_slot_ctx_t * slot_ctx,
ulong prev_epoch,
const fd_hash_t * parent_blockhash,
fd_calculate_rewards_and_distribute_vote_rewards_result_t * result
fd_calculate_rewards_and_distribute_vote_rewards_result_t * result,
fd_epoch_info_t *temp_info
) {
/* https://github.com/firedancer-io/solana/blob/dab3da8e7b667d7527565bddbdbecf7ec1fb868e/runtime/src/bank.rs#L2406-L2492 */
fd_partitioned_rewards_calculation_t rewards_calc_result[1] = {0};
calculate_rewards_for_partitioning( slot_ctx, prev_epoch, parent_blockhash, rewards_calc_result );
calculate_rewards_for_partitioning( slot_ctx, prev_epoch, parent_blockhash, rewards_calc_result, temp_info );

/* Iterate over all the vote reward nodes */
for ( fd_vote_reward_t_mapnode_t* vote_reward_node = fd_vote_reward_t_map_minimum(
Expand Down Expand Up @@ -1099,7 +988,8 @@ void
fd_update_rewards(
fd_exec_slot_ctx_t * slot_ctx,
const fd_hash_t * parent_blockhash,
ulong parent_epoch
ulong parent_epoch,
fd_epoch_info_t * temp_info
) {

/* https://github.com/anza-xyz/agave/blob/7117ed9653ce19e8b2dea108eff1f3eb6a3378a7/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L55 */
Expand All @@ -1108,7 +998,8 @@ fd_update_rewards(
slot_ctx,
parent_epoch,
parent_blockhash,
rewards_result
rewards_result,
temp_info
);

/* Distribute all of the partitioned epoch rewards in one go */
Expand All @@ -1129,16 +1020,18 @@ void
fd_begin_partitioned_rewards(
fd_exec_slot_ctx_t * slot_ctx,
const fd_hash_t * parent_blockhash,
ulong parent_epoch
ulong parent_epoch,
fd_epoch_info_t * temp_info
) {
FD_SCRATCH_SCOPE_BEGIN {
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(
slot_ctx,
parent_epoch,
parent_blockhash,
rewards_result
rewards_result,
temp_info
);

/* https://github.com/anza-xyz/agave/blob/9a7bf72940f4b3cd7fc94f54e005868ce707d53d/runtime/src/bank/partitioned_epoch_rewards/calculation.rs#L62 */
Expand All @@ -1159,7 +1052,7 @@ FD_SCRATCH_SCOPE_BEGIN {
rewards_result->point_value,
parent_blockhash
);
} FD_SCRATCH_SCOPE_END;
} FD_SCRATCH_SCOPE_END;
}

/*
Expand Down
6 changes: 4 additions & 2 deletions src/flamenco/rewards/fd_rewards.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,15 @@ FD_PROTOTYPES_BEGIN
void
fd_update_rewards( fd_exec_slot_ctx_t * slot_ctx,
const fd_hash_t * parent_blockhash,
ulong parent_epoch );
ulong parent_epoch,
fd_epoch_info_t * temp_info );

void
fd_begin_partitioned_rewards(
fd_exec_slot_ctx_t * slot_ctx,
const fd_hash_t * parent_blockhash,
ulong parent_epoch );
ulong parent_epoch,
fd_epoch_info_t * temp_info );

void
fd_rewards_recalculate_partitioned_rewards(
Expand Down
Loading

0 comments on commit 4617bd4

Please sign in to comment.