diff --git a/contrib/test/test-vectors-fixtures/instr-fixtures/stake.list b/contrib/test/test-vectors-fixtures/instr-fixtures/stake.list index ee167a23d9..7c69900da6 100644 --- a/contrib/test/test-vectors-fixtures/instr-fixtures/stake.list +++ b/contrib/test/test-vectors-fixtures/instr-fixtures/stake.list @@ -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 diff --git a/src/flamenco/rewards/fd_rewards.c b/src/flamenco/rewards/fd_rewards.c index 227feaee2a..f94ccfd40d 100644 --- a/src/flamenco/rewards/fd_rewards.c +++ b/src/flamenco/rewards/fd_rewards.c @@ -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; @@ -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 */ @@ -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 ); @@ -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; @@ -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; @@ -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 ); @@ -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( @@ -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; @@ -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, @@ -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( @@ -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 */ @@ -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 */ @@ -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 */ @@ -1159,7 +1052,7 @@ FD_SCRATCH_SCOPE_BEGIN { rewards_result->point_value, parent_blockhash ); -} FD_SCRATCH_SCOPE_END; + } FD_SCRATCH_SCOPE_END; } /* diff --git a/src/flamenco/rewards/fd_rewards.h b/src/flamenco/rewards/fd_rewards.h index 7500fad1d2..26f5b5452b 100644 --- a/src/flamenco/rewards/fd_rewards.h +++ b/src/flamenco/rewards/fd_rewards.h @@ -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( diff --git a/src/flamenco/runtime/context/fd_exec_epoch_ctx.c b/src/flamenco/runtime/context/fd_exec_epoch_ctx.c index 9202effc3b..16147f844f 100644 --- a/src/flamenco/runtime/context/fd_exec_epoch_ctx.c +++ b/src/flamenco/runtime/context/fd_exec_epoch_ctx.c @@ -19,19 +19,15 @@ fd_exec_epoch_ctx_footprint_ext( fd_exec_epoch_ctx_layout_t * layout, fd_memset( layout, 0, sizeof(fd_exec_epoch_ctx_layout_t) ); layout->vote_acc_max = vote_acc_max; - ulong stake_votes_sz = fd_vote_accounts_pair_t_map_footprint( vote_acc_max ); if( !stake_votes_sz ) return 0UL; - ulong stake_delegations_sz = fd_delegation_pair_t_map_footprint ( vote_acc_max ); if( !stake_delegations_sz ) return 0UL; - ulong stake_history_treap_sz = fd_stake_history_treap_footprint( FD_SYSVAR_STAKE_HISTORY_CAP ); if( !stake_history_treap_sz ) FD_LOG_CRIT(( "invalid fd_stake_history_treap footprint" )); - ulong stake_history_pool_sz = fd_stake_history_pool_footprint ( FD_SYSVAR_STAKE_HISTORY_CAP ); if( !stake_history_pool_sz ) FD_LOG_CRIT(( "invalid fd_stake_history_pool footprint" )); + ulong stake_votes_sz = fd_vote_accounts_pair_t_map_footprint( vote_acc_max ); if( !stake_votes_sz ) return 0UL; + ulong stake_delegations_sz = fd_delegation_pair_t_map_footprint ( vote_acc_max ); if( !stake_delegations_sz ) return 0UL; ulong next_epoch_stakes_sz = fd_vote_accounts_pair_t_map_footprint( vote_acc_max ); if( !next_epoch_stakes_sz ) return 0UL; - ulong leaders_sz = fd_epoch_leaders_footprint( MAX_PUB_CNT, MAX_SLOTS_CNT ); if( !leaders_sz ) FD_LOG_CRIT(( "invalid fd_epoch_leaders footprint" )); + ulong leaders_sz = fd_epoch_leaders_footprint( MAX_PUB_CNT, MAX_SLOTS_CNT ); if( !leaders_sz ) FD_LOG_CRIT(( "invalid fd_epoch_leaders footprint" )); FD_SCRATCH_ALLOC_INIT( l, 0 ); FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_exec_epoch_ctx_t), sizeof(fd_exec_epoch_ctx_t) ); layout->stake_votes_off = (ulong)FD_SCRATCH_ALLOC_APPEND( l, fd_vote_accounts_pair_t_map_align(), stake_votes_sz ); layout->stake_delegations_off = (ulong)FD_SCRATCH_ALLOC_APPEND( l, fd_delegation_pair_t_map_align(), stake_delegations_sz ); - layout->stake_history_treap_off = (ulong)FD_SCRATCH_ALLOC_APPEND( l, fd_stake_history_treap_align(), stake_history_treap_sz ); - layout->stake_history_pool_off = (ulong)FD_SCRATCH_ALLOC_APPEND( l, fd_stake_history_pool_align(), stake_history_pool_sz ); layout->next_epoch_stakes_off = (ulong)FD_SCRATCH_ALLOC_APPEND( l, fd_vote_accounts_pair_t_map_align(), next_epoch_stakes_sz ); layout->leaders_off = (ulong)FD_SCRATCH_ALLOC_APPEND( l, fd_epoch_leaders_align(), leaders_sz ); @@ -70,7 +66,7 @@ fd_exec_epoch_ctx_new( void * mem, fd_features_disable_all( &self->features ); self->epoch_bank.cluster_version[0] = FD_DEFAULT_AGAVE_CLUSTER_VERSION_MAJOR; self->epoch_bank.cluster_version[1] = FD_DEFAULT_AGAVE_CLUSTER_VERSION_MINOR; - self->epoch_bank.cluster_version[2] = FD_DEFAULT_AGAVE_CLUSTER_VERSION_PATCH; + self->epoch_bank.cluster_version[2] = FD_DEFAULT_AGAVE_CLUSTER_VERSION_PATCH; fd_features_enable_cleaned_up( &self->features, self->epoch_bank.cluster_version ); FD_COMPILER_MFENCE(); @@ -104,13 +100,9 @@ epoch_ctx_bank_mem_leave( fd_exec_epoch_ctx_t * epoch_ctx ) { void * stake_votes_mem = (void *)( (ulong)mem + layout->stake_votes_off ); void * stake_delegations_mem = (void *)( (ulong)mem + layout->stake_delegations_off ); - void * stake_history_treap_mem = (void *)( (ulong)mem + layout->stake_history_treap_off ); - void * stake_history_pool_mem = (void *)( (ulong)mem + layout->stake_history_pool_off ); fd_vote_accounts_pair_t_map_leave ( stake_votes_mem ); fd_delegation_pair_t_map_leave ( stake_delegations_mem ); - fd_stake_history_treap_leave ( stake_history_treap_mem ); - (void)fd_stake_history_pool_leave ( stake_history_pool_mem ); } void * @@ -171,13 +163,9 @@ epoch_ctx_bank_mem_delete( fd_exec_epoch_ctx_t * epoch_ctx ) { void * stake_votes_mem = (void *)( (ulong)mem + layout->stake_votes_off ); void * stake_delegations_mem = (void *)( (ulong)mem + layout->stake_delegations_off ); - void * stake_history_treap_mem = (void *)( (ulong)mem + layout->stake_history_treap_off ); - void * stake_history_pool_mem = (void *)( (ulong)mem + layout->stake_history_pool_off ); fd_vote_accounts_pair_t_map_delete( stake_votes_mem ); fd_delegation_pair_t_map_delete ( stake_delegations_mem ); - fd_stake_history_treap_delete ( stake_history_treap_mem ); - fd_stake_history_pool_delete ( stake_history_pool_mem ); } void @@ -201,26 +189,6 @@ fd_exec_epoch_ctx_bank_mem_clear( fd_exec_epoch_ctx_t * epoch_ctx ) { fd_delegation_pair_t_map_release_tree( old_pool, old_root ); epoch_bank->stakes.stake_delegations_root = NULL; } - { - fd_stake_history_entry_t * old_pool = epoch_bank->stakes.stake_history.pool; - fd_stake_history_treap_t * old_treap = epoch_bank->stakes.stake_history.treap; - - if ( old_pool && old_treap ) { - ulong elem_cnt = 0UL; - ulong keys[FD_SYSVAR_STAKE_HISTORY_CAP] = {0}; - for( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init( old_treap, old_pool ); - !fd_stake_history_treap_fwd_iter_done( iter ); - iter = fd_stake_history_treap_fwd_iter_next( iter, old_pool ) ) { - fd_stake_history_entry_t const * ele = fd_stake_history_treap_fwd_iter_ele_const( iter, old_pool ); - keys[elem_cnt++] = ele->epoch; - } - for (ulong i=0UL; inext_epoch_stakes.vote_accounts_pool; fd_vote_accounts_pair_t_mapnode_t * old_root = epoch_bank->next_epoch_stakes.vote_accounts_root; @@ -235,8 +203,6 @@ fd_exec_epoch_ctx_bank_mem_setup( fd_exec_epoch_ctx_t * self ) { void * stake_votes_mem = (void *)( (ulong)self + layout->stake_votes_off ); void * stake_delegations_mem = (void *)( (ulong)self + layout->stake_delegations_off ); - void * stake_history_treap_mem = (void *)( (ulong)self + layout->stake_history_treap_off ); - void * stake_history_pool_mem = (void *)( (ulong)self + layout->stake_history_pool_off ); void * next_epoch_stakes_mem = (void *)( (ulong)self + layout->next_epoch_stakes_off ); //void * leaders_mem = (void *)( (ulong)self + layout->leaders_off ); @@ -249,11 +215,6 @@ fd_exec_epoch_ctx_bank_mem_setup( fd_exec_epoch_ctx_t * self ) { epoch_bank->stakes.stake_delegations_pool = fd_delegation_pair_t_map_join ( fd_delegation_pair_t_map_new ( stake_delegations_mem, layout->vote_acc_max ) ); - epoch_bank->stakes.stake_history.treap = - fd_stake_history_treap_join ( fd_stake_history_treap_new ( stake_history_treap_mem, FD_SYSVAR_STAKE_HISTORY_CAP ) ); - epoch_bank->stakes.stake_history.pool = - fd_stake_history_pool_join ( fd_stake_history_pool_new ( stake_history_pool_mem, FD_SYSVAR_STAKE_HISTORY_CAP ) ); - epoch_bank->next_epoch_stakes.vote_accounts_pool = fd_vote_accounts_pair_t_map_join( fd_vote_accounts_pair_t_map_new( next_epoch_stakes_mem, layout->vote_acc_max ) ); diff --git a/src/flamenco/runtime/context/fd_exec_epoch_ctx.h b/src/flamenco/runtime/context/fd_exec_epoch_ctx.h index 9a1133923d..448c7f5bd5 100644 --- a/src/flamenco/runtime/context/fd_exec_epoch_ctx.h +++ b/src/flamenco/runtime/context/fd_exec_epoch_ctx.h @@ -15,8 +15,6 @@ struct fd_exec_epoch_ctx_layout { ulong stake_votes_off; ulong stake_delegations_off; - ulong stake_history_treap_off; - ulong stake_history_pool_off; ulong next_epoch_stakes_off; ulong leaders_off; /* Current epoch only */ }; @@ -102,18 +100,6 @@ fd_exec_epoch_ctx_stake_delegations_join( fd_exec_epoch_ctx_t * ctx ) { return fd_delegation_pair_t_map_join( mem ); } -FD_FN_PURE static inline fd_stake_history_treap_t * -fd_exec_epoch_ctx_stake_history_treap_join( fd_exec_epoch_ctx_t * ctx ) { - void * mem = (void *)((ulong)ctx + ctx->layout.stake_history_treap_off); - return fd_stake_history_treap_join( mem ); -} - -FD_FN_PURE static inline fd_stake_history_entry_t * -fd_exec_epoch_ctx_stake_history_pool_join( fd_exec_epoch_ctx_t * ctx ) { - void * mem = (void *)((ulong)ctx + ctx->layout.stake_history_pool_off); - return fd_stake_history_pool_join( mem ); -} - FD_FN_PURE static inline fd_vote_accounts_pair_t_mapnode_t * fd_exec_epoch_ctx_next_epoch_stakes_join( fd_exec_epoch_ctx_t * ctx ) { void * mem = (void *)((ulong)ctx + ctx->layout.next_epoch_stakes_off); diff --git a/src/flamenco/runtime/context/fd_exec_slot_ctx.c b/src/flamenco/runtime/context/fd_exec_slot_ctx.c index df48b3443d..70b31320bc 100644 --- a/src/flamenco/runtime/context/fd_exec_slot_ctx.c +++ b/src/flamenco/runtime/context/fd_exec_slot_ctx.c @@ -216,28 +216,7 @@ fd_exec_slot_ctx_recover_( fd_exec_slot_ctx_t * slot_ctx, } /* Copy stakes->stake_history */ - for ( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init( - oldbank->stakes.stake_history.treap, - oldbank->stakes.stake_history.pool ); - !fd_stake_history_treap_fwd_iter_done( iter ); - iter = fd_stake_history_treap_fwd_iter_next( iter, oldbank->stakes.stake_history.pool ) ) { - - fd_stake_history_entry_t const * ele = fd_stake_history_treap_fwd_iter_ele_const( iter, oldbank->stakes.stake_history.pool ); - - FD_TEST( fd_stake_history_pool_free( epoch_bank->stakes.stake_history.pool ) ); - fd_stake_history_entry_t * new_ele = fd_stake_history_pool_ele_acquire( epoch_bank->stakes.stake_history.pool ); - - new_ele->epoch = ele->epoch; - new_ele->activating = ele->activating; - new_ele->deactivating = ele->deactivating; - new_ele->effective = ele->effective; - - epoch_bank->stakes.stake_history.treap = fd_stake_history_treap_ele_insert( - epoch_bank->stakes.stake_history.treap, - new_ele, - epoch_bank->stakes.stake_history.pool - ); - } + fd_memcpy( &epoch_bank->stakes.stake_history, &oldbank->stakes.stake_history, sizeof(oldbank->stakes.stake_history)); fd_stakes_destroy( &oldbank->stakes, &destroy ); @@ -327,7 +306,7 @@ fd_exec_slot_ctx_recover_( fd_exec_slot_ctx_t * slot_ctx, do { ulong epoch = fd_slot_to_epoch( &epoch_bank->epoch_schedule, slot_bank->slot, NULL ); - /* We need to save the vote accounts for the current epoch and the next + /* We need to save the vote accounts for the current epoch and the next epoch as it is used to calculate the leader schedule at the epoch boundary. */ diff --git a/src/flamenco/runtime/fd_runtime.c b/src/flamenco/runtime/fd_runtime.c index 51cd0b8428..7e76f81d5d 100644 --- a/src/flamenco/runtime/fd_runtime.c +++ b/src/flamenco/runtime/fd_runtime.c @@ -127,9 +127,6 @@ fd_runtime_init_bank_from_genesis( fd_exec_slot_ctx_t * slot_ctx, fd_delegation_pair_t_mapnode_t * sacc_pool = fd_exec_epoch_ctx_stake_delegations_join( epoch_ctx ); fd_delegation_pair_t_mapnode_t * sacc_root = NULL; - fd_stake_history_treap_t * stake_history_treap = fd_exec_epoch_ctx_stake_history_treap_join( epoch_ctx ); - fd_stake_history_entry_t * stake_history_pool = fd_exec_epoch_ctx_stake_history_pool_join ( epoch_ctx ); - fd_acc_lamports_t capitalization = 0UL; for (ulong i = 0UL; i < genesis_block->accounts_len; i++) { @@ -299,8 +296,7 @@ fd_runtime_init_bank_from_genesis( fd_exec_slot_ctx_t * slot_ctx, .unused = 0, .vote_accounts = (fd_vote_accounts_t){ .vote_accounts_pool = vacc_pool, - .vote_accounts_root = vacc_root}, - .stake_history = (fd_stake_history_t){.pool = stake_history_pool, .treap = stake_history_treap}}; + .vote_accounts_root = vacc_root}}; slot_ctx->slot_bank.capitalization = capitalization; @@ -3847,8 +3843,7 @@ fd_features_activate( fd_exec_slot_ctx_t * slot_ctx ) { void fd_runtime_update_leaders(fd_exec_slot_ctx_t *slot_ctx, ulong slot) { - FD_SCRATCH_SCOPE_BEGIN - { + FD_SCRATCH_SCOPE_BEGIN { fd_epoch_schedule_t schedule = slot_ctx->epoch_ctx->epoch_bank.epoch_schedule; FD_LOG_INFO(("schedule->slots_per_epoch = %lu", schedule.slots_per_epoch)); @@ -3891,8 +3886,7 @@ void fd_runtime_update_leaders(fd_exec_slot_ctx_t *slot_ctx, ulong slot) fd_epoch_leaders_t * leaders = fd_epoch_leaders_join(fd_epoch_leaders_new(epoch_leaders_mem, epoch, slot0, slot_cnt, stake_weight_cnt, epoch_weights, 0UL)); FD_TEST(leaders); } - } - FD_SCRATCH_SCOPE_END; + } FD_SCRATCH_SCOPE_END; } /* Update the epoch bank stakes cache with the delegated stake values from the slot bank cache. @@ -3905,123 +3899,90 @@ As delegations have to warm up, the contents of the cache will not change inter- the cache only at epoch boundaries. https://github.com/solana-labs/solana/blob/c091fd3da8014c0ef83b626318018f238f506435/runtime/src/stakes.rs#L65 */ -void fd_update_stake_delegations(fd_exec_slot_ctx_t * slot_ctx ) { -FD_SCRATCH_SCOPE_BEGIN { - fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); - fd_stakes_t * stakes = &epoch_bank->stakes; - - // TODO: is this size correct if the same stake account is in both the slot and epoch cache? Is this possible? - ulong stake_delegations_size = fd_delegation_pair_t_map_size( - stakes->stake_delegations_pool, stakes->stake_delegations_root ); - stake_delegations_size += fd_stake_accounts_pair_t_map_size( - slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root ); - - // Create a new epoch stake delegations cache, which will hold the union of the slot and epoch caches. - fd_delegation_pair_t_mapnode_t * new_stake_root = NULL; - fd_delegation_pair_t_mapnode_t * new_stake_pool = fd_delegation_pair_t_map_alloc( fd_scratch_virtual(), stake_delegations_size ); - - // Add the stake delegations from the epoch bank to the new epoch stake delegations cache. - for( fd_delegation_pair_t_mapnode_t const * n = fd_delegation_pair_t_map_minimum_const( stakes->stake_delegations_pool, stakes->stake_delegations_root ); - n; - n = fd_delegation_pair_t_map_successor_const( stakes->stake_delegations_pool, n ) ) { - fd_pubkey_t const * stake_acc = &n->elem.account; - FD_BORROWED_ACCOUNT_DECL(stake_acc_rec); - if (fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, stake_acc, stake_acc_rec ) != FD_ACC_MGR_SUCCESS ) { - continue; - } +static +void fd_update_stake_delegations(fd_exec_slot_ctx_t * slot_ctx, fd_epoch_info_t *temp_info ) { + FD_SCRATCH_SCOPE_BEGIN { + fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); + fd_stakes_t * stakes = &epoch_bank->stakes; - fd_stake_state_v2_t stake_state; - if (fd_stake_get_state( stake_acc_rec, &slot_ctx->valloc, &stake_state) != 0) { - continue; - } - fd_delegation_pair_t_mapnode_t * entry = fd_delegation_pair_t_map_acquire( new_stake_pool ); - fd_memcpy(&entry->elem.account, stake_acc, sizeof(fd_pubkey_t)); - fd_memcpy(&entry->elem.delegation, &stake_state.inner.stake.stake.delegation, sizeof(fd_delegation_t)); - fd_delegation_pair_t_map_insert( new_stake_pool, &new_stake_root, entry ); - } + // TODO: is this size correct if the same stake account is in both the slot and epoch cache? Is this possible? + ulong stake_delegations_size = fd_delegation_pair_t_map_size( + stakes->stake_delegations_pool, stakes->stake_delegations_root ); + stake_delegations_size += fd_stake_accounts_pair_t_map_size( + slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root ); - // Add the stake delegations from the slot bank to the new epoch stake delegations cache. - 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 ) ) { - fd_pubkey_t const * stake_acc = &n->elem.key; - FD_BORROWED_ACCOUNT_DECL(stake_acc_rec); - if (fd_acc_mgr_view( slot_ctx->acc_mgr, slot_ctx->funk_txn, stake_acc, stake_acc_rec ) != FD_ACC_MGR_SUCCESS ) { - continue; - } + // Create a new epoch stake delegations cache, which will hold the union of the slot and epoch caches. + fd_delegation_pair_t_mapnode_t * new_stake_root = NULL; + fd_delegation_pair_t_mapnode_t * new_stake_pool = fd_delegation_pair_t_map_alloc( fd_scratch_virtual(), stake_delegations_size ); - fd_stake_state_v2_t stake_state; - if (fd_stake_get_state( stake_acc_rec, &slot_ctx->valloc, &stake_state) != 0) { - continue; - } + for ( ulong idx = 0; idx < temp_info->infos_len; idx++ ) { + // Fetch the delegation associated with this stake account fd_delegation_pair_t_mapnode_t * entry = fd_delegation_pair_t_map_acquire( new_stake_pool ); - fd_memcpy(&entry->elem.account, stake_acc, sizeof(fd_pubkey_t)); - fd_memcpy(&entry->elem.delegation, &stake_state.inner.stake.stake.delegation, sizeof(fd_delegation_t)); + fd_memcpy(&entry->elem.account, &temp_info->infos[idx].account, sizeof(fd_pubkey_t)); + fd_memcpy(&entry->elem.delegation, &temp_info->infos[idx].stake.delegation, sizeof(fd_delegation_t)); fd_delegation_pair_t_map_insert( new_stake_pool, &new_stake_root, entry ); - } + } - // Update the epoch bank vote_accounts with the latest values from the slot bank - // FIXME: resize the vote_accounts_pool if necessary - ulong total_epoch_stake = 0UL; - for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum( - slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, - slot_ctx->slot_bank.vote_account_keys.vote_accounts_root ); - n; - n = fd_vote_accounts_pair_t_map_successor( slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, n ) ) { + // Update the epoch bank vote_accounts with the latest values from the slot bank + // FIXME: resize the vote_accounts_pool if necessary + ulong total_epoch_stake = 0UL; + for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum( + slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, + slot_ctx->slot_bank.vote_account_keys.vote_accounts_root ); + n; + n = fd_vote_accounts_pair_t_map_successor( slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool, n ) ) { - // If the vote account is not in the epoch stakes cache, insert it - fd_vote_accounts_pair_t_mapnode_t key; - fd_memcpy( &key.elem.key, &n->elem.key, FD_PUBKEY_FOOTPRINT ); - fd_vote_accounts_pair_t_mapnode_t * epoch_cache_node = fd_vote_accounts_pair_t_map_find( stakes->vote_accounts.vote_accounts_pool, stakes->vote_accounts.vote_accounts_root, &key ); - if( epoch_cache_node == NULL ) { - epoch_cache_node = fd_vote_accounts_pair_t_map_acquire( stakes->vote_accounts.vote_accounts_pool ); + // If the vote account is not in the epoch stakes cache, insert it + fd_vote_accounts_pair_t_mapnode_t key; + fd_memcpy( &key.elem.key, &n->elem.key, FD_PUBKEY_FOOTPRINT ); + fd_vote_accounts_pair_t_mapnode_t * epoch_cache_node = fd_vote_accounts_pair_t_map_find( stakes->vote_accounts.vote_accounts_pool, stakes->vote_accounts.vote_accounts_root, &key ); + if( epoch_cache_node == NULL ) { + epoch_cache_node = fd_vote_accounts_pair_t_map_acquire( stakes->vote_accounts.vote_accounts_pool ); - fd_memcpy(&epoch_cache_node->elem.key, &n->elem.key, sizeof(fd_pubkey_t)); - fd_memcpy(&epoch_cache_node->elem.stake, &n->elem.stake, sizeof(ulong)); - fd_memcpy(&epoch_cache_node->elem.value, &n->elem.value, sizeof(fd_solana_account_t)); + fd_memcpy(&epoch_cache_node->elem.key, &n->elem.key, sizeof(fd_pubkey_t)); + fd_memcpy(&epoch_cache_node->elem.stake, &n->elem.stake, sizeof(ulong)); + fd_memcpy(&epoch_cache_node->elem.value, &n->elem.value, sizeof(fd_solana_account_t)); - fd_vote_accounts_pair_t_map_insert( stakes->vote_accounts.vote_accounts_pool, &stakes->vote_accounts.vote_accounts_root, epoch_cache_node ); - } else { - epoch_cache_node->elem.stake = n->elem.stake; + fd_vote_accounts_pair_t_map_insert( stakes->vote_accounts.vote_accounts_pool, &stakes->vote_accounts.vote_accounts_root, epoch_cache_node ); + } else { + epoch_cache_node->elem.stake = n->elem.stake; + } + total_epoch_stake += epoch_cache_node->elem.stake; } - total_epoch_stake += epoch_cache_node->elem.stake; - } - slot_ctx->epoch_ctx->total_epoch_stake = total_epoch_stake; - - fd_bincode_destroy_ctx_t destroy_slot = {.valloc = slot_ctx->valloc}; - fd_vote_accounts_destroy( &slot_ctx->slot_bank.vote_account_keys, &destroy_slot ); - fd_stake_accounts_destroy(&slot_ctx->slot_bank.stake_account_keys, &destroy_slot ); - - /* Release all nodes in tree. - FIXME sweep pool and ignore tree nodes might is probably faster - than recursive descent */ - fd_delegation_pair_t_map_release_tree( stakes->stake_delegations_pool, stakes->stake_delegations_root ); - stakes->stake_delegations_root = NULL; - - for( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum( new_stake_pool, new_stake_root ); n; n = fd_delegation_pair_t_map_successor( new_stake_pool, n ) ) { - fd_delegation_pair_t_mapnode_t * e = fd_delegation_pair_t_map_acquire( stakes->stake_delegations_pool ); - if( FD_UNLIKELY( !e ) ) { - FD_LOG_CRIT(( "Stake delegation map overflowed! (capacity=%lu)", fd_delegation_pair_t_map_max( stakes->stake_delegations_pool ) )); + slot_ctx->epoch_ctx->total_epoch_stake = total_epoch_stake; + + fd_bincode_destroy_ctx_t destroy_slot = {.valloc = slot_ctx->valloc}; + fd_vote_accounts_destroy( &slot_ctx->slot_bank.vote_account_keys, &destroy_slot ); + fd_stake_accounts_destroy(&slot_ctx->slot_bank.stake_account_keys, &destroy_slot ); + + /* Release all nodes in tree. + FIXME sweep pool and ignore tree nodes might is probably faster + than recursive descent */ + fd_delegation_pair_t_map_release_tree( stakes->stake_delegations_pool, stakes->stake_delegations_root ); + stakes->stake_delegations_root = NULL; + + for( fd_delegation_pair_t_mapnode_t * n = fd_delegation_pair_t_map_minimum( new_stake_pool, new_stake_root ); n; n = fd_delegation_pair_t_map_successor( new_stake_pool, n ) ) { + fd_delegation_pair_t_mapnode_t * e = fd_delegation_pair_t_map_acquire( stakes->stake_delegations_pool ); + if( FD_UNLIKELY( !e ) ) { + FD_LOG_CRIT(( "Stake delegation map overflowed! (capacity=%lu)", fd_delegation_pair_t_map_max( stakes->stake_delegations_pool ) )); + } + fd_memcpy( &e->elem.account, &n->elem.account, sizeof(fd_pubkey_t)); + fd_memcpy( &e->elem.delegation, &n->elem.delegation, sizeof(fd_delegation_t)); + fd_delegation_pair_t_map_insert( stakes->stake_delegations_pool, &stakes->stake_delegations_root, e ); } - fd_memcpy( &e->elem.account, &n->elem.account, sizeof(fd_pubkey_t)); - fd_memcpy( &e->elem.delegation, &n->elem.delegation, sizeof(fd_delegation_t)); - fd_delegation_pair_t_map_insert( stakes->stake_delegations_pool, &stakes->stake_delegations_root, e ); - } - slot_ctx->slot_bank.stake_account_keys.stake_accounts_root = NULL; - slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool = fd_stake_accounts_pair_t_map_alloc( slot_ctx->valloc, 100000 ); + slot_ctx->slot_bank.stake_account_keys.stake_accounts_root = NULL; + slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool = fd_stake_accounts_pair_t_map_alloc( slot_ctx->valloc, 100000 ); - slot_ctx->slot_bank.vote_account_keys.vote_accounts_root = NULL; - slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool = fd_vote_accounts_pair_t_map_alloc( slot_ctx->valloc, 100000 ); -} FD_SCRATCH_SCOPE_END; + slot_ctx->slot_bank.vote_account_keys.vote_accounts_root = NULL; + slot_ctx->slot_bank.vote_account_keys.vote_accounts_pool = fd_vote_accounts_pair_t_map_alloc( slot_ctx->valloc, 100000 ); + } FD_SCRATCH_SCOPE_END; } /* Replace the stakes in T-2 (slot_ctx->slot_bank.epoch_stakes) by the stakes at T-1 (epoch_bank->next_epoch_stakes) */ static void fd_update_epoch_stakes( fd_exec_slot_ctx_t * slot_ctx ) { - FD_SCRATCH_SCOPE_BEGIN - { + FD_SCRATCH_SCOPE_BEGIN { fd_epoch_bank_t * epoch_bank = &slot_ctx->epoch_ctx->epoch_bank; /* Copy epoch_bank->next_epoch_stakes into slot_ctx->slot_bank.epoch_stakes */ @@ -4054,15 +4015,13 @@ void fd_update_epoch_stakes( fd_exec_slot_ctx_t * slot_ctx ) { &slot_ctx->slot_bank.epoch_stakes.vote_accounts_root, elem ); } - } - FD_SCRATCH_SCOPE_END; + } FD_SCRATCH_SCOPE_END; } /* Copy epoch_bank->stakes.vote_accounts into epoch_bank->next_epoch_stakes. */ static void fd_update_next_epoch_stakes( fd_exec_slot_ctx_t * slot_ctx ) { - FD_SCRATCH_SCOPE_BEGIN - { + FD_SCRATCH_SCOPE_BEGIN { fd_epoch_bank_t * epoch_bank = &slot_ctx->epoch_ctx->epoch_bank; /* Copy epoch_ctx->epoch_bank->stakes.vote_accounts into epoch_bank->next_epoch_stakes */ @@ -4082,8 +4041,7 @@ void fd_update_next_epoch_stakes( fd_exec_slot_ctx_t * slot_ctx ) { fd_memcpy( &elem->elem, &n->elem, sizeof(fd_vote_accounts_pair_t)); fd_vote_accounts_pair_t_map_insert( epoch_bank->next_epoch_stakes.vote_accounts_pool, &epoch_bank->next_epoch_stakes.vote_accounts_root, elem ); } - } - FD_SCRATCH_SCOPE_END; + } FD_SCRATCH_SCOPE_END; } /* Mimics `bank.new_target_program_account()`. Assumes `out_rec` is a modifiable record. @@ -4445,6 +4403,8 @@ void fd_process_new_epoch( fd_exec_slot_ctx_t *slot_ctx, ulong parent_epoch ) { + FD_LOG_NOTICE(( "fd_process_new_epoch start" )); + ulong slot; fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); ulong epoch = fd_slot_to_epoch(&epoch_bank->epoch_schedule, slot_ctx->slot_bank.slot, &slot); @@ -4479,45 +4439,56 @@ void fd_process_new_epoch( new_rate_activation_epoch = NULL; } - /* Updates stake history sysvar accumulated values. */ - fd_stakes_activate_epoch( slot_ctx, new_rate_activation_epoch ); + FD_SCRATCH_SCOPE_BEGIN { - /* Update the stakes epoch value to the new epoch */ - epoch_bank->stakes.epoch = epoch; + fd_epoch_info_t temp_info; + fd_epoch_info_new( &temp_info ); - /* If appropiate, use the stakes at T-1 to generate the leader schedule instead of T-2. - This is due to a subtlety in how Agave's stake caches interact when loading from snapshots. - See the comment in fd_exec_slot_ctx_recover_. */ - if( slot_ctx->slot_bank.has_use_preceeding_epoch_stakes && slot_ctx->slot_bank.use_preceeding_epoch_stakes == epoch ) { - fd_update_epoch_stakes( slot_ctx ); - } + /* Updates stake history sysvar accumulated values. */ + fd_stakes_activate_epoch( slot_ctx, new_rate_activation_epoch, &temp_info ); - /* Distribute rewards */ - fd_hash_t const * parent_blockhash = slot_ctx->slot_bank.block_hash_queue.last_hash; - if ( ( FD_FEATURE_ACTIVE( slot_ctx, enable_partitioned_epoch_reward ) || - FD_FEATURE_ACTIVE( slot_ctx, partitioned_epoch_rewards_superfeature ) ) ) { - fd_begin_partitioned_rewards( slot_ctx, parent_blockhash, parent_epoch ); - } else { - fd_update_rewards( slot_ctx, parent_blockhash, parent_epoch ); - } + /* Update the stakes epoch value to the new epoch */ + epoch_bank->stakes.epoch = epoch; - /* Updates stakes at time T */ - 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" )); + /* If appropiate, use the stakes at T-1 to generate the leader schedule instead of T-2. + This is due to a subtlety in how Agave's stake caches interact when loading from snapshots. + See the comment in fd_exec_slot_ctx_recover_. */ + if( slot_ctx->slot_bank.has_use_preceeding_epoch_stakes && slot_ctx->slot_bank.use_preceeding_epoch_stakes == epoch ) { + fd_update_epoch_stakes( slot_ctx ); + } - refresh_vote_accounts( slot_ctx, history, new_rate_activation_epoch ); - fd_update_stake_delegations( slot_ctx ); + /* Distribute rewards */ + fd_hash_t const * parent_blockhash = slot_ctx->slot_bank.block_hash_queue.last_hash; + if ( ( FD_FEATURE_ACTIVE( slot_ctx, enable_partitioned_epoch_reward ) || + FD_FEATURE_ACTIVE( slot_ctx, partitioned_epoch_rewards_superfeature ) ) ) { + FD_LOG_NOTICE(( "fd_begin_partitioned_rewards" )); + fd_begin_partitioned_rewards( slot_ctx, parent_blockhash, parent_epoch, &temp_info ); + } else { + fd_update_rewards( slot_ctx, parent_blockhash, parent_epoch, &temp_info ); + } + + /* Updates stakes at time T */ + 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" )); + + FD_LOG_NOTICE(( "refresh_vote_accounts" )); - /* Replace stakes at T-2 (slot_ctx->slot_bank.epoch_stakes) by stakes at T-1 (epoch_bank->next_epoch_stakes) */ - fd_update_epoch_stakes( slot_ctx ); + refresh_vote_accounts( slot_ctx, history, new_rate_activation_epoch, &temp_info ); + fd_update_stake_delegations( slot_ctx, &temp_info ); - /* Replace stakes at T-1 (epoch_bank->next_epoch_stakes) by updated stakes at T (stakes->vote_accounts) */ - fd_update_next_epoch_stakes( slot_ctx ); + /* Replace stakes at T-2 (slot_ctx->slot_bank.epoch_stakes) by stakes at T-1 (epoch_bank->next_epoch_stakes) */ + fd_update_epoch_stakes( slot_ctx ); + + /* Replace stakes at T-1 (epoch_bank->next_epoch_stakes) by updated stakes at T (stakes->vote_accounts) */ + fd_update_next_epoch_stakes( slot_ctx ); - /* Update current leaders using slot_ctx->slot_bank.epoch_stakes (new T-2 stakes) */ - fd_runtime_update_leaders( slot_ctx, slot_ctx->slot_bank.slot ); + /* Update current leaders using slot_ctx->slot_bank.epoch_stakes (new T-2 stakes) */ + fd_runtime_update_leaders( slot_ctx, slot_ctx->slot_bank.slot ); + + fd_calculate_epoch_accounts_hash_values( slot_ctx ); + } FD_SCRATCH_SCOPE_END; - fd_calculate_epoch_accounts_hash_values( slot_ctx ); + FD_LOG_NOTICE(( "fd_process_new_epoch end" )); } /* Loads the sysvar cache. Expects acc_mgr, funk_txn, valloc to be non-NULL and valid. */ diff --git a/src/flamenco/runtime/program/fd_stake_program.c b/src/flamenco/runtime/program/fd_stake_program.c index c3ea761272..82725031a9 100644 --- a/src/flamenco/runtime/program/fd_stake_program.c +++ b/src/flamenco/runtime/program/fd_stake_program.c @@ -151,7 +151,7 @@ set_state( fd_exec_instr_ctx_t const * ctx, uchar * data = NULL; ulong dlen = 0UL; - + int err = fd_account_get_data_mut( ctx, acct_idx, &data, &dlen ); if( FD_UNLIKELY( err ) ) return err; @@ -442,6 +442,26 @@ set_lockup_meta( fd_stake_meta_t * self, typedef fd_stake_history_entry_t fd_stake_activation_status_t; +fd_stake_history_entry_t const * +fd_stake_history_ele_query_const( fd_stake_history_t const * history, + ulong epoch ) { + if( 0 == history->fd_stake_history_len ) + return NULL; + + if( epoch > history->fd_stake_history[0].epoch ) + return NULL; + + ulong off = (history->fd_stake_history[0].epoch - epoch); + if( off >= history->fd_stake_history_len ) + return NULL; + + ulong e = (off + history->fd_stake_history_offset) & (history->fd_stake_history_size - 1); + + FD_TEST(history->fd_stake_history[e].epoch == epoch); + + return &history->fd_stake_history[e]; +} + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L728 static effective_activating_t stake_and_activating( fd_delegation_t const * self, @@ -461,8 +481,8 @@ stake_and_activating( fd_delegation_t const * self, } else if( target_epochactivation_epoch ) { return ( effective_activating_t ){ .effective = 0, .activating = 0 }; } else if( history && - ( cluster_stake_at_activation_epoch = fd_stake_history_treap_ele_query_const( - history->treap, self->activation_epoch, history->pool ) ) ) { + ( cluster_stake_at_activation_epoch = fd_stake_history_ele_query_const( + history, self->activation_epoch ) ) ) { ulong prev_epoch = self->activation_epoch; fd_stake_history_entry_t const * prev_cluster_stake = cluster_stake_at_activation_epoch; @@ -502,9 +522,8 @@ stake_and_activating( fd_delegation_t const * self, // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L796-L801 fd_stake_history_entry_t const * current_cluster_stake = - fd_stake_history_treap_ele_query_const( history->treap, current_epoch, history->pool ); - if( FD_UNLIKELY( current_cluster_stake = fd_stake_history_treap_ele_query_const( - history->treap, current_epoch, history->pool ) ) ) { + fd_stake_history_ele_query_const( history, current_epoch ); + if( FD_UNLIKELY( NULL != current_cluster_stake ) ) { prev_epoch = current_epoch; prev_cluster_stake = current_cluster_stake; } else { @@ -535,7 +554,7 @@ stake_activating_and_deactivating( fd_delegation_t const * self, ulong effective_stake = effective_activating.effective; ulong activating_stake = effective_activating.activating; - fd_stake_history_entry_t * cluster_stake_at_activation_epoch = NULL; + fd_stake_history_entry_t const * cluster_stake_at_activation_epoch = NULL; fd_stake_history_entry_t k; k.epoch = self->deactivation_epoch; @@ -556,8 +575,7 @@ stake_activating_and_deactivating( fd_delegation_t const * self, .effective = effective_stake, .deactivating = effective_stake, .activating = 0 }; } else if( stake_history!=NULL ) { // https://github.com/anza-xyz/agave/blob/be16321eb0db3e12a57a32f59febbf54b92ebb7c/sdk/program/src/stake/state.rs#L665 - fd_stake_history_entry_t * n = - fd_stake_history_treap_ele_query( stake_history->treap, k.epoch, stake_history->pool ); + fd_stake_history_entry_t const * n = fd_stake_history_ele_query_const( stake_history, k.epoch ); if( NULL!=n ) { cluster_stake_at_activation_epoch = n; } @@ -567,7 +585,7 @@ stake_activating_and_deactivating( fd_delegation_t const * self, return entry; } ulong prev_epoch = self->deactivation_epoch; - fd_stake_history_entry_t * prev_cluster_stake = cluster_stake_at_activation_epoch; + fd_stake_history_entry_t const * prev_cluster_stake = cluster_stake_at_activation_epoch; ulong current_epoch; ulong current_effective_stake = effective_stake; @@ -592,9 +610,8 @@ stake_activating_and_deactivating( fd_delegation_t const * self, if( current_epoch>=target_epoch ) break; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L711-L713 - fd_stake_history_entry_t * current_cluster_stake = NULL; - if( ( current_cluster_stake = fd_stake_history_treap_ele_query( - stake_history->treap, current_epoch, stake_history->pool ) ) ) { + fd_stake_history_entry_t const * current_cluster_stake = NULL; + if( ( current_cluster_stake = fd_stake_history_ele_query_const(stake_history, current_epoch ) ) ) { prev_epoch = current_epoch; prev_cluster_stake = current_cluster_stake; } else { @@ -825,7 +842,7 @@ get_if_mergeable( fd_exec_instr_ctx_t * invoke_context, // not const to // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1117 } else if( status.activating==0 && status.deactivating==0 ) { *out = ( merge_kind_t ){ .discriminant = merge_kind_fully_active, - .inner = { .fully_active = { .meta = *meta, + .inner = { .fully_active = { .meta = *meta, .stake = *stake } } }; return 0; } else { @@ -1364,7 +1381,7 @@ delegate( fd_exec_instr_ctx_t const * ctx, fd_stake_state_v2_t stake_state = {0}; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L330 FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) { - + rc = get_state( stake_account, fd_scratch_virtual(), &stake_state ); if( FD_UNLIKELY( rc ) ) return rc; @@ -1405,7 +1422,7 @@ delegate( fd_exec_instr_ctx_t const * ctx, // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L346 rc = authorized_check( &meta.authorized, signers, STAKE_AUTHORIZE_STAKER ); if( FD_UNLIKELY( rc ) ) return rc; - + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L347-L348 validated_delegated_info_t validated_delegated_info; rc = validate_delegated_amount( stake_account, @@ -1434,7 +1451,7 @@ delegate( fd_exec_instr_ctx_t const * ctx, .meta = meta, .stake = stake, .stake_flags = stake_flags } } }; - + return set_state( ctx, stake_account_index, &new_stake_state ); } default: @@ -1549,11 +1566,11 @@ split( fd_exec_instr_ctx_t const * ctx, fd_stake_state_v2_t stake_state = {0}; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L420 FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account) { - + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L422 if( FD_UNLIKELY( lamports>stake_account->const_meta->info.lamports ) ) return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS; - + rc = get_state( stake_account, fd_scratch_virtual(), &stake_state ); if( FD_UNLIKELY( rc ) ) return rc; @@ -1571,7 +1588,7 @@ split( fd_exec_instr_ctx_t const * ctx, if( FD_UNLIKELY( rc ) ) return rc; // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L431 ulong minimum_delegation = get_minimum_delegation( ctx->slot_ctx ); - + int is_active; if( FD_UNLIKELY( FD_FEATURE_ACTIVE( ctx->slot_ctx, require_rent_exempt_split_destination ) ) ) { @@ -1605,7 +1622,7 @@ split( fd_exec_instr_ctx_t const * ctx, ulong remaining_stake_delta; ulong split_stake_amount; // FIXME FD_LIKELY - + if( validated_split_info.source_remaining_balance==0 ) { // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L456 remaining_stake_delta = fd_ulong_sat_sub( lamports, meta->rent_exempt_reserve ); @@ -1691,7 +1708,7 @@ split( fd_exec_instr_ctx_t const * ctx, // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L518 FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, split_index, split ) { - + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L520 fd_stake_state_v2_t temp = { .discriminant = fd_stake_state_v2_enum_initialized, .inner = { .initialized = { .meta = split_meta } } }; @@ -1730,7 +1747,7 @@ split( fd_exec_instr_ctx_t const * ctx, // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L542 FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, split_index, split ) { - + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L544 rc = fd_account_checked_add_lamports( ctx, split_index, lamports ); if( FD_UNLIKELY( rc ) ) return rc; @@ -1849,7 +1866,7 @@ merge( fd_exec_instr_ctx_t * ctx, // not const to log } // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L136 -static int +static int move_stake_or_lamports_shared_checks( fd_exec_instr_ctx_t * invoke_context, // not const to log fd_borrowed_account_t * source_account, ulong lamports, @@ -1861,7 +1878,7 @@ move_stake_or_lamports_shared_checks( fd_exec_instr_ctx_t * invoke_context, // int rc; // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L145-L153 - if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( invoke_context->instr, stake_authority_index ) ) ) { + if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( invoke_context->instr, stake_authority_index ) ) ) { return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE; } @@ -1885,7 +1902,7 @@ move_stake_or_lamports_shared_checks( fd_exec_instr_ctx_t * invoke_context, // // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L173 if( lamports==0 ) 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_cache_clock( invoke_context->slot_ctx->sysvar_cache ); if( FD_UNLIKELY( !clock ) ) @@ -1926,7 +1943,7 @@ move_stake_or_lamports_shared_checks( fd_exec_instr_ctx_t * invoke_context, // destination_merge_kind, &invoke_context->txn_ctx->custom_err ); if( FD_UNLIKELY( rc ) ) return rc; - + // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L206 rc = metas_can_merge( invoke_context, meta( source_merge_kind ), meta( destination_merge_kind ), clock, custom_err ); if( FD_UNLIKELY( rc ) ) return rc; @@ -1947,7 +1964,7 @@ move_stake(fd_exec_instr_ctx_t * ctx, // not const to log // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L798-L804 FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, source_account_index, source_account ) { FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, destination_account_index, destination_account ) { - + // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L804 merge_kind_t source_merge_kind = {0}; merge_kind_t destination_merge_kind = {0}; @@ -1973,7 +1990,7 @@ move_stake(fd_exec_instr_ctx_t * ctx, // not const to log fd_stake_t * source_stake = &source_merge_kind.inner.fully_active.stake; // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L827 - ulong minimum_delegation = get_minimum_delegation( ctx->slot_ctx ); + ulong minimum_delegation = get_minimum_delegation( ctx->slot_ctx ); // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L831 if( FD_UNLIKELY( source_stake->delegation.stakedelegation.stake - lamports; - // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L836 + // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L836 if( FD_UNLIKELY( source_final_stake!=0 && source_final_stakedelegation.stake = source_final_stake; - + fd_stake_state_v2_t new_source_state = { .discriminant = fd_stake_state_v2_enum_stake, .inner = { .stake = { .meta = *source_meta, .stake = *source_stake, @@ -2081,7 +2098,7 @@ move_stake(fd_exec_instr_ctx_t * ctx, // not const to log if( FD_UNLIKELY( fd_account_get_lamports2( ctx, source_account_index )rent_exempt_reserve ) || fd_account_get_lamports2( ctx, destination_account_index )rent_exempt_reserve ) { fd_log_collector_msg_literal( ctx, "Delegation calculations violated lamport balance assumptions" ); - return FD_EXECUTOR_INSTR_ERR_INVALID_ARG; + return FD_EXECUTOR_INSTR_ERR_INVALID_ARG; } } FD_BORROWED_ACCOUNT_DROP( destination_account ); @@ -2124,7 +2141,7 @@ move_lamports(fd_exec_instr_ctx_t * ctx, // not const to log source_free_lamports = fd_ulong_sat_sub( fd_ulong_sat_sub( source_account->const_meta->info.lamports, source_merge_kind.inner.fully_active.stake.delegation.stake ), source_merge_kind.inner.fully_active.meta.rent_exempt_reserve ); - + break; } case merge_kind_inactive: { @@ -2179,7 +2196,7 @@ withdraw( fd_exec_instr_ctx_t const * ctx, // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L819 FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) { - + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L821 fd_stake_state_v2_t stake_state = {0}; rc = get_state( stake_account, fd_scratch_virtual(), &stake_state ); @@ -2308,7 +2325,7 @@ withdraw( fd_exec_instr_ctx_t const * ctx, if( FD_UNLIKELY( rc ) ) return rc; } FD_BORROWED_ACCOUNT_DROP( to ); - + return 0; } @@ -2376,7 +2393,7 @@ deactivate_delinquent( fd_exec_instr_ctx_t * ctx, return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR; } - // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L944 + // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L944 if( FD_LIKELY( eligible_for_deactivate_delinquent( delinquent_vote_state.epoch_credits, current_epoch ) ) ) { rc = stake_deactivate( stake, current_epoch, custom_err ); @@ -2761,7 +2778,7 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { * * Instruction: * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L165 - * + * * Processor: * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L217 */ @@ -3041,8 +3058,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { /* MoveStake * * Instruction: - * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/sdk/program/src/stake/instruction.rs#L330 - * + * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/sdk/program/src/stake/instruction.rs#L330 + * * Processor: * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L356 */ @@ -3070,8 +3087,8 @@ fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) { /* MoveLamports * * Instruction: - * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/sdk/program/src/stake/instruction.rs#L345 - * + * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/sdk/program/src/stake/instruction.rs#L345 + * * Processor: * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L375 */ diff --git a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c index 25b0bf5d2c..6210eb032f 100644 --- a/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c +++ b/src/flamenco/runtime/sysvar/fd_sysvar_stake_history.c @@ -5,7 +5,6 @@ /* Ensure that the size declared by our header matches the minimum size of the corresponding fd_types entry. */ -FD_STATIC_ASSERT( FD_SYSVAR_STAKE_HISTORY_CAP == FD_STAKE_HISTORY_MIN, types ); static void write_stake_history( fd_exec_slot_ctx_t * slot_ctx, @@ -44,10 +43,8 @@ fd_sysvar_stake_history_read( fd_stake_history_t * result, void fd_sysvar_stake_history_init( fd_exec_slot_ctx_t * slot_ctx ) { - fd_stake_history_t stake_history = { - .pool = fd_stake_history_pool_alloc ( slot_ctx->valloc, FD_SYSVAR_STAKE_HISTORY_CAP ), - .treap = fd_stake_history_treap_alloc( slot_ctx->valloc, FD_SYSVAR_STAKE_HISTORY_CAP ) - }; + fd_stake_history_t stake_history; + fd_stake_history_new( &stake_history ); write_stake_history( slot_ctx, &stake_history ); } @@ -58,25 +55,21 @@ fd_sysvar_stake_history_update( fd_exec_slot_ctx_t * slot_ctx, fd_stake_history_t stake_history; fd_sysvar_stake_history_read( &stake_history, slot_ctx, &slot_ctx->valloc ); - if (fd_stake_history_treap_ele_cnt( stake_history.treap ) == fd_stake_history_treap_ele_max( stake_history.treap )) { - fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init( stake_history.treap, stake_history.pool ); - fd_stake_history_entry_t * ele = fd_stake_history_treap_fwd_iter_ele( iter, stake_history.pool ); - stake_history.treap = fd_stake_history_treap_ele_remove( stake_history.treap, ele, stake_history.pool ); - fd_stake_history_pool_ele_release( stake_history.pool, ele ); - } - - if( 0 == fd_stake_history_pool_free( stake_history.pool ) ) { - FD_LOG_ERR(( "stake_history.pool is empty" )); - } + if( stake_history.fd_stake_history_offset == 0 ) + stake_history.fd_stake_history_offset = stake_history.fd_stake_history_size - 1; + else + stake_history.fd_stake_history_offset--; - ulong idx = fd_stake_history_pool_idx_acquire( stake_history.pool ); + if( stake_history.fd_stake_history_len < stake_history.fd_stake_history_size) + stake_history.fd_stake_history_len++; - stake_history.pool[ idx ].epoch = entry->epoch; - stake_history.pool[ idx ].activating = entry->activating; - stake_history.pool[ idx ].effective = entry->effective; - stake_history.pool[ idx ].deactivating = entry->deactivating; - stake_history.treap = fd_stake_history_treap_idx_insert( stake_history.treap, idx, stake_history.pool ); + // This should be done with a bit mask + ulong idx = stake_history.fd_stake_history_offset; + stake_history.fd_stake_history[ idx ].epoch = entry->epoch; + stake_history.fd_stake_history[ idx ].activating = entry->activating; + stake_history.fd_stake_history[ idx ].effective = entry->effective; + stake_history.fd_stake_history[ idx ].deactivating = entry->deactivating; write_stake_history( slot_ctx, &stake_history); fd_bincode_destroy_ctx_t destroy = { .valloc = slot_ctx->valloc }; diff --git a/src/flamenco/stakes/fd_stakes.c b/src/flamenco/stakes/fd_stakes.c index 0d8f66c4ad..0a4095227b 100644 --- a/src/flamenco/stakes/fd_stakes.c +++ b/src/flamenco/stakes/fd_stakes.c @@ -161,7 +161,9 @@ stake account. void refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, fd_stake_history_t const * history, - ulong * new_rate_activation_epoch ) { + ulong * new_rate_activation_epoch, + fd_epoch_info_t *temp_info + ) { fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); fd_stakes_t * stakes = &epoch_bank->stakes; @@ -174,26 +176,9 @@ refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, fd_stake_weight_t_mapnode_t * root = NULL; // Iterate over each stake delegation and accumulate the stake amount associated with the given vote account. - 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) ) { - - // Get the stake account - FD_BORROWED_ACCOUNT_DECL(stake_acc); - int rc = fd_acc_mgr_view(slot_ctx->acc_mgr, slot_ctx->funk_txn, &n->elem.account, stake_acc); - if ( FD_UNLIKELY( rc != FD_ACC_MGR_SUCCESS || stake_acc->const_meta->info.lamports == 0 ) ) { - continue; - } - - fd_stake_state_v2_t stake_state; - rc = fd_stake_get_state( stake_acc, &slot_ctx->valloc, &stake_state ); - if ( FD_UNLIKELY( rc != 0) ) { - continue; - } - + for ( ulong idx = 0; idx < temp_info->infos_len; idx++ ) { // Fetch the delegation associated with this stake account - fd_delegation_t * delegation = &stake_state.inner.stake.stake.delegation; + fd_delegation_t * delegation = &temp_info->infos[idx].stake.delegation; fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, stakes->epoch, history, new_rate_activation_epoch ); @@ -212,43 +197,6 @@ refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx, } } - // Also include delegations from the stake accounts in the current slot context's - // slot_ctx->slot_bank.stake_account_keys (a set of the stake accounts which we have - // from this epoch). - for ( fd_stake_accounts_pair_t_mapnode_t * n = fd_stake_accounts_pair_t_map_minimum( - 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( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, n ) ) { - FD_BORROWED_ACCOUNT_DECL(stake_acc); - int rc = fd_acc_mgr_view(slot_ctx->acc_mgr, slot_ctx->funk_txn, &n->elem.key, stake_acc); - if ( FD_UNLIKELY( rc != FD_ACC_MGR_SUCCESS || stake_acc->const_meta->info.lamports == 0 ) ) { - continue; - } - - fd_stake_state_v2_t stake_state; - rc = fd_stake_get_state( stake_acc, &slot_ctx->valloc, &stake_state ); - if ( FD_UNLIKELY( rc != 0) ) { - continue; - } - - fd_delegation_t * delegation = &stake_state.inner.stake.stake.delegation; - fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, stakes->epoch, history, new_rate_activation_epoch ); - - ulong delegation_stake = new_entry.effective; - fd_stake_weight_t_mapnode_t temp; - fd_memcpy(&temp.elem.key, &delegation->voter_pubkey, sizeof(fd_pubkey_t)); - fd_stake_weight_t_mapnode_t * entry = fd_stake_weight_t_map_find(pool, root, &temp); - if (entry != NULL) { - entry->elem.stake += delegation_stake; - } else { - entry = fd_stake_weight_t_map_acquire( pool ); - fd_memcpy( &entry->elem.key, &delegation->voter_pubkey, sizeof(fd_pubkey_t)); - entry->elem.stake = delegation_stake; - fd_stake_weight_t_map_insert( pool, &root, entry ); - } - } - // Copy the delegated stake values calculated above to the epoch bank stakes vote_accounts for ( fd_vote_accounts_pair_t_mapnode_t * n = fd_vote_accounts_pair_t_map_minimum( @@ -277,8 +225,9 @@ 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, - ulong * new_rate_activation_epoch ) { - + ulong * new_rate_activation_epoch, + fd_epoch_info_t *temp_info + ) { fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx ); fd_stakes_t * stakes = &epoch_bank->stakes; @@ -288,7 +237,16 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, https://github.com/solana-labs/solana/blob/88aeaa82a856fc807234e7da0b31b89f2dc0e091/runtime/src/stakes.rs#L181-L192 */ 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" )); + if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "StakeHistory sysvar is missing from sysvar cache" )); + + ulong stake_delegations_size = fd_delegation_pair_t_map_size( + stakes->stake_delegations_pool, stakes->stake_delegations_root ); + stake_delegations_size += fd_stake_accounts_pair_t_map_size( + slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root ); + temp_info->infos_len = stake_delegations_size; + temp_info->infos = (fd_epoch_info_pair_t *)fd_scratch_alloc( FD_EPOCH_INFO_PAIR_ALIGN, FD_EPOCH_INFO_PAIR_FOOTPRINT*stake_delegations_size ); + fd_memset( temp_info->infos, 0, FD_EPOCH_INFO_PAIR_FOOTPRINT*stake_delegations_size ); + ulong delegation_idx = 0; fd_stake_history_entry_t accumulator = { .effective = 0, @@ -312,7 +270,17 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, continue; } + if ( FD_UNLIKELY( !fd_stake_state_v2_is_stake( &stake_state ) ) ) { + continue; + } + + if( FD_UNLIKELY( stake_state.inner.stake.stake.delegation.stake == 0 ) ) { + continue; + } + fd_delegation_t * delegation = &stake_state.inner.stake.stake.delegation; + fd_memcpy(&temp_info->infos[delegation_idx ].stake, &stake_state.inner.stake.stake, sizeof(fd_stake_t)); + fd_memcpy(&temp_info->infos[delegation_idx++].account, &n->elem.account, sizeof(fd_pubkey_t)); fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, stakes->epoch, history, new_rate_activation_epoch ); accumulator.effective += new_entry.effective; accumulator.activating += new_entry.activating; @@ -347,7 +315,17 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, continue; } + if ( FD_UNLIKELY( !fd_stake_state_v2_is_stake( &stake_state ) ) ) { + continue; + } + + if( FD_UNLIKELY( stake_state.inner.stake.stake.delegation.stake == 0 ) ) { + continue; + } + fd_delegation_t * delegation = &stake_state.inner.stake.stake.delegation; + fd_memcpy(&temp_info->infos[delegation_idx ].stake.delegation, &stake_state.inner.stake.stake, sizeof(fd_stake_t)); + fd_memcpy(&temp_info->infos[delegation_idx++].account, &n->elem.key, sizeof(fd_pubkey_t)); fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, stakes->epoch, history, new_rate_activation_epoch ); accumulator.effective += new_entry.effective; accumulator.activating += new_entry.activating; @@ -367,6 +345,8 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, } } + temp_info->infos_len = delegation_idx; + fd_stake_history_entry_t new_elem = { .epoch = stakes->epoch, .effective = accumulator.effective, diff --git a/src/flamenco/stakes/fd_stakes.h b/src/flamenco/stakes/fd_stakes.h index 88b4a2eb68..f0e970bd6f 100644 --- a/src/flamenco/stakes/fd_stakes.h +++ b/src/flamenco/stakes/fd_stakes.h @@ -30,7 +30,9 @@ fd_stake_weights_by_node( fd_vote_accounts_t const * accs, void fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx, - ulong * new_rate_activation_epoch ); + ulong * new_rate_activation_epoch, + fd_epoch_info_t *temp_info + ); 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 ); @@ -49,7 +51,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, - ulong * new_rate_activation_epoch ); + ulong * new_rate_activation_epoch, + fd_epoch_info_t *temp_info ); FD_PROTOTYPES_END diff --git a/src/flamenco/types/fd_bincode.h b/src/flamenco/types/fd_bincode.h index 80b6152ef5..48d0b0172e 100644 --- a/src/flamenco/types/fd_bincode.h +++ b/src/flamenco/types/fd_bincode.h @@ -448,6 +448,7 @@ enum { FD_ARCHIVE_META_TREAP = 0x25, FD_ARCHIVE_META_OPTION = 0x26, FD_ARCHIVE_META_ARRAY = 0x27, + FD_ARCHIVE_META_STATIC_VECTOR = 0x28, }; #define FD_ARCHIVE_META_SENTINAL (ushort)0 /* End of structure */ diff --git a/src/flamenco/types/fd_type_names.c b/src/flamenco/types/fd_type_names.c index 506184f6c5..c58206d85f 100644 --- a/src/flamenco/types/fd_type_names.c +++ b/src/flamenco/types/fd_type_names.c @@ -1,5 +1,5 @@ // This is an auto-generated file. To add entries, edit fd_types.json -#define FD_TYPE_NAME_COUNT 230 +#define FD_TYPE_NAME_COUNT 232 static char const * fd_type_names[FD_TYPE_NAME_COUNT] = { "fd_hash", "fd_pubkey", @@ -31,6 +31,8 @@ static char const * fd_type_names[FD_TYPE_NAME_COUNT] = { "fd_delegation", "fd_delegation_pair", "fd_stake", + "fd_epoch_info_pair", + "fd_epoch_info", "fd_stake_pair", "fd_stakes", "fd_stakes_stake", diff --git a/src/flamenco/types/fd_types.c b/src/flamenco/types/fd_types.c index b9df2fc90a..f19eb7b3be 100644 --- a/src/flamenco/types/fd_types.c +++ b/src/flamenco/types/fd_types.c @@ -2299,10 +2299,6 @@ enum { fd_stake_history_entry_effective_TAG = (1 << 6) | FD_ARCHIVE_META_ULONG, fd_stake_history_entry_activating_TAG = (2 << 6) | FD_ARCHIVE_META_ULONG, fd_stake_history_entry_deactivating_TAG = (3 << 6) | FD_ARCHIVE_META_ULONG, - fd_stake_history_entry_parent_TAG = (4 << 6) | FD_ARCHIVE_META_ULONG, - fd_stake_history_entry_left_TAG = (5 << 6) | FD_ARCHIVE_META_ULONG, - fd_stake_history_entry_right_TAG = (6 << 6) | FD_ARCHIVE_META_ULONG, - fd_stake_history_entry_prio_TAG = (7 << 6) | FD_ARCHIVE_META_ULONG, }; int fd_stake_history_entry_decode_archival( fd_stake_history_entry_t * self, fd_bincode_decode_ctx_t * ctx ) { void const * data = ctx->data; @@ -2419,10 +2415,6 @@ int fd_stake_history_entry_decode_offsets( fd_stake_history_entry_off_t * self, self->deactivating_off = (uint)( (ulong)ctx->data - (ulong)data ); err = fd_bincode_uint64_decode_preflight( ctx ); if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; - self->parent_off = (uint)( (ulong)ctx->data - (ulong)data ); - self->left_off = (uint)( (ulong)ctx->data - (ulong)data ); - self->right_off = (uint)( (ulong)ctx->data - (ulong)data ); - self->prio_off = (uint)( (ulong)ctx->data - (ulong)data ); return FD_BINCODE_SUCCESS; } void fd_stake_history_entry_new(fd_stake_history_entry_t * self) { @@ -2464,52 +2456,39 @@ int fd_stake_history_decode( fd_stake_history_t * self, fd_bincode_decode_ctx_t } int fd_stake_history_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { int err; - ulong fd_stake_history_treap_len; - err = fd_bincode_uint64_decode( &fd_stake_history_treap_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( ulong i=0; i < fd_stake_history_treap_len; i++ ) { - err = fd_stake_history_entry_decode_preflight( ctx ); - if( FD_UNLIKELY ( err ) ) return err; + ulong fd_stake_history_len; + err = fd_bincode_uint64_decode( &fd_stake_history_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( fd_stake_history_len ) { + for( ulong i=0; i < fd_stake_history_len; i++ ) { + err = fd_stake_history_entry_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } } return FD_BINCODE_SUCCESS; } void fd_stake_history_decode_unsafe( fd_stake_history_t * self, fd_bincode_decode_ctx_t * ctx ) { - ulong fd_stake_history_treap_len; - fd_bincode_uint64_decode_unsafe( &fd_stake_history_treap_len, ctx ); - if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { - ulong fd_stake_history_treap_max = fd_ulong_max( fd_stake_history_treap_len, FD_STAKE_HISTORY_MIN ); - self->pool = fd_stake_history_pool_alloc( ctx->valloc, fd_stake_history_treap_max ); - self->treap = fd_stake_history_treap_alloc( ctx->valloc, fd_stake_history_treap_max ); - } - for( ulong i=0; i < fd_stake_history_treap_len; i++ ) { - fd_stake_history_entry_t * ele = fd_stake_history_pool_ele_acquire( self->pool ); - fd_stake_history_entry_new( ele ); - fd_stake_history_entry_decode_unsafe( ele, ctx ); - fd_stake_history_treap_ele_insert( self->treap, ele, self->pool ); /* this cannot fail */ + fd_bincode_uint64_decode_unsafe( &self->fd_stake_history_len, ctx ); + self->fd_stake_history_size = 512; + self->fd_stake_history_offset = 0; + for( ulong i=0; ifd_stake_history_len; i++ ) { + fd_stake_history_entry_decode_unsafe( self->fd_stake_history + i, ctx ); } } int fd_stake_history_encode( fd_stake_history_t const * self, fd_bincode_encode_ctx_t * ctx ) { int err; - if( self->treap ) { - ulong fd_stake_history_len = fd_stake_history_treap_ele_cnt( self->treap ); - err = fd_bincode_uint64_encode( fd_stake_history_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( fd_stake_history_treap_rev_iter_t iter = fd_stake_history_treap_rev_iter_init( self->treap, self->pool ); - !fd_stake_history_treap_rev_iter_done( iter ); - iter = fd_stake_history_treap_rev_iter_next( iter, self->pool ) ) { - fd_stake_history_entry_t * ele = fd_stake_history_treap_rev_iter_ele( iter, self->pool ); - err = fd_stake_history_entry_encode( ele, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - } else { - ulong fd_stake_history_len = 0; - err = fd_bincode_uint64_encode( fd_stake_history_len, ctx ); + err = fd_bincode_uint64_encode( self->fd_stake_history_len, ctx ); + if( FD_UNLIKELY(err) ) return err; + if( FD_UNLIKELY( 0 == self->fd_stake_history_len ) ) return FD_BINCODE_SUCCESS; + for( ulong i=0; ifd_stake_history_len; i++ ) { + ulong idx = ( i + self->fd_stake_history_offset ) & (512 - 1); + err = fd_stake_history_entry_encode( self->fd_stake_history + idx, ctx ); if( FD_UNLIKELY( err ) ) return err; } return FD_BINCODE_SUCCESS; } enum { - fd_stake_history_fd_stake_history_TAG = (0 << 6) | FD_ARCHIVE_META_TREAP, + fd_stake_history_fd_stake_history_TAG = (0 << 6) | FD_ARCHIVE_META_STATIC_VECTOR, }; int fd_stake_history_decode_archival( fd_stake_history_t * self, fd_bincode_decode_ctx_t * ctx ) { void const * data = ctx->data; @@ -2534,12 +2513,14 @@ int fd_stake_history_decode_archival_preflight( fd_bincode_decode_ctx_t * ctx ) case (ushort)fd_stake_history_fd_stake_history_TAG: { err = fd_archive_decode_setup_length( ctx, &offset ); if( FD_UNLIKELY( err ) ) return err; - ulong fd_stake_history_treap_len; - err = fd_bincode_uint64_decode( &fd_stake_history_treap_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( ulong i=0; i < fd_stake_history_treap_len; i++ ) { - err = fd_stake_history_entry_decode_archival_preflight( ctx ); - if( FD_UNLIKELY ( err ) ) return err; + ulong fd_stake_history_len; + err = fd_bincode_uint64_decode( &fd_stake_history_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( fd_stake_history_len ) { + for( ulong i=0; i < fd_stake_history_len; i++ ) { + err = fd_stake_history_entry_decode_archival_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } } err = fd_archive_decode_check_length( ctx, offset ); if( FD_UNLIKELY( err ) ) return err; @@ -2562,18 +2543,11 @@ void fd_stake_history_decode_archival_unsafe( fd_stake_history_t * self, fd_binc switch( tag ) { case (ushort)fd_stake_history_fd_stake_history_TAG: { fd_archive_decode_setup_length( ctx, &offset ); - ulong fd_stake_history_treap_len; - fd_bincode_uint64_decode_unsafe( &fd_stake_history_treap_len, ctx ); - if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { - ulong fd_stake_history_treap_max = fd_ulong_max( fd_stake_history_treap_len, FD_STAKE_HISTORY_MIN ); - self->pool = fd_stake_history_pool_alloc( ctx->valloc, fd_stake_history_treap_max ); - self->treap = fd_stake_history_treap_alloc( ctx->valloc, fd_stake_history_treap_max ); - } - for( ulong i=0; i < fd_stake_history_treap_len; i++ ) { - fd_stake_history_entry_t * ele = fd_stake_history_pool_ele_acquire( self->pool ); - fd_stake_history_entry_new( ele ); - fd_stake_history_entry_decode_archival_unsafe( ele, ctx ); - fd_stake_history_treap_ele_insert( self->treap, ele, self->pool ); /* this cannot fail */ + fd_bincode_uint64_decode_unsafe( &self->fd_stake_history_len, ctx ); + self->fd_stake_history_size = 512; + self->fd_stake_history_offset = 0; + for( ulong i=0; ifd_stake_history_len; i++ ) { + fd_stake_history_entry_decode_archival_unsafe( self->fd_stake_history + i, ctx ); } break; } @@ -2590,20 +2564,12 @@ int fd_stake_history_encode_archival( fd_stake_history_t const * self, fd_bincod if( FD_UNLIKELY( err ) ) return err; err = fd_archive_encode_setup_length( ctx, &offset ); if( FD_UNLIKELY( err ) ) return err; - if( self->treap ) { - ulong fd_stake_history_len = fd_stake_history_treap_ele_cnt( self->treap ); - err = fd_bincode_uint64_encode( fd_stake_history_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( fd_stake_history_treap_rev_iter_t iter = fd_stake_history_treap_rev_iter_init( self->treap, self->pool ); - !fd_stake_history_treap_rev_iter_done( iter ); - iter = fd_stake_history_treap_rev_iter_next( iter, self->pool ) ) { - fd_stake_history_entry_t * ele = fd_stake_history_treap_rev_iter_ele( iter, self->pool ); - err = fd_stake_history_entry_encode_archival( ele, ctx ); - if( FD_UNLIKELY( err ) ) return err; - } - } else { - ulong fd_stake_history_len = 0; - err = fd_bincode_uint64_encode( fd_stake_history_len, ctx ); + err = fd_bincode_uint64_encode( self->fd_stake_history_len, ctx ); + if( FD_UNLIKELY(err) ) return err; + if( FD_UNLIKELY( 0 == self->fd_stake_history_len ) ) return FD_BINCODE_SUCCESS; + for( ulong i=0; ifd_stake_history_len; i++ ) { + ulong idx = ( i + self->fd_stake_history_offset ) & (512 - 1); + err = fd_stake_history_entry_encode_archival( self->fd_stake_history + idx, ctx ); if( FD_UNLIKELY( err ) ) return err; } err = fd_archive_encode_set_length( ctx, offset ); @@ -2616,30 +2582,26 @@ int fd_stake_history_decode_offsets( fd_stake_history_off_t * self, fd_bincode_d uchar const * data = ctx->data; int err; self->fd_stake_history_off = (uint)( (ulong)ctx->data - (ulong)data ); - ulong fd_stake_history_treap_len; - err = fd_bincode_uint64_decode( &fd_stake_history_treap_len, ctx ); - if( FD_UNLIKELY( err ) ) return err; - for( ulong i=0; i < fd_stake_history_treap_len; i++ ) { - err = fd_stake_history_entry_decode_preflight( ctx ); - if( FD_UNLIKELY ( err ) ) return err; + ulong fd_stake_history_len; + err = fd_bincode_uint64_decode( &fd_stake_history_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( fd_stake_history_len ) { + for( ulong i=0; i < fd_stake_history_len; i++ ) { + err = fd_stake_history_entry_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } } return FD_BINCODE_SUCCESS; } void fd_stake_history_new(fd_stake_history_t * self) { fd_memset( self, 0, sizeof(fd_stake_history_t) ); + self->fd_stake_history_size = 512; + for( ulong i=0; i<512; i++ ) + fd_stake_history_entry_new( self->fd_stake_history + i ); } void fd_stake_history_destroy( fd_stake_history_t * self, fd_bincode_destroy_ctx_t * ctx ) { - if( !self->treap || !self->pool ) return; - for( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init( self->treap, self->pool ); - !fd_stake_history_treap_fwd_iter_done( iter ); - iter = fd_stake_history_treap_fwd_iter_next( iter, self->pool ) ) { - fd_stake_history_entry_t * ele = fd_stake_history_treap_fwd_iter_ele( iter, self->pool ); - fd_stake_history_entry_destroy( ele, ctx ); - } - fd_valloc_free( ctx->valloc, fd_stake_history_treap_delete(fd_stake_history_treap_leave( self->treap) ) ); - fd_valloc_free( ctx->valloc, fd_stake_history_pool_delete(fd_stake_history_pool_leave( self->pool) ) ); - self->pool = NULL; - self->treap = NULL; + for( ulong i=0; i<512; i++ ) + fd_stake_history_entry_destroy( self->fd_stake_history + i, ctx ); } ulong fd_stake_history_footprint( void ){ return FD_STAKE_HISTORY_FOOTPRINT; } @@ -2647,27 +2609,19 @@ ulong fd_stake_history_align( void ){ return FD_STAKE_HISTORY_ALIGN; } void fd_stake_history_walk( void * w, fd_stake_history_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_stake_history", level++ ); - if( self->treap ) { - for( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init( self->treap, self->pool ); - !fd_stake_history_treap_fwd_iter_done( iter ); - iter = fd_stake_history_treap_fwd_iter_next( iter, self->pool ) ) { - fd_stake_history_entry_t * ele = fd_stake_history_treap_fwd_iter_ele( iter, self->pool ); - fd_stake_history_entry_walk( w, ele, fun, "fd_stake_history_entry_t", level ); - } + fun( w, NULL, "fd_stake_history", FD_FLAMENCO_TYPE_ARR, "stake_history_entry[]", level++ ); + for( ulong i=0; ifd_stake_history_len; i++ ) { + ulong idx = ( i + self->fd_stake_history_offset ) & (512 - 1); + fd_stake_history_entry_walk( w, self->fd_stake_history + idx, fun, "stake_history_entry", level ); } + fun( w, NULL, "fd_stake_history", FD_FLAMENCO_TYPE_ARR_END, "stake_history_entry[]", level-- ); fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_stake_history", level-- ); } ulong fd_stake_history_size( fd_stake_history_t const * self ) { ulong size = 0; size += sizeof(ulong); - if( self->treap ) { - for( fd_stake_history_treap_fwd_iter_t iter = fd_stake_history_treap_fwd_iter_init( self->treap, self->pool ); - !fd_stake_history_treap_fwd_iter_done( iter ); - iter = fd_stake_history_treap_fwd_iter_next( iter, self->pool ) ) { - fd_stake_history_entry_t * ele = fd_stake_history_treap_fwd_iter_ele( iter, self->pool ); - size += fd_stake_history_entry_size( ele ); - } - } + for( ulong i=0; ifd_stake_history_len; i++ ) + size += fd_stake_history_entry_size( self->fd_stake_history + i ); return size; } @@ -4164,6 +4118,171 @@ ulong fd_stake_size( fd_stake_t const * self ) { return size; } +int fd_epoch_info_pair_decode( fd_epoch_info_pair_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_epoch_info_pair_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_epoch_info_pair_new( self ); + } + fd_epoch_info_pair_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_epoch_info_pair_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + err = fd_bincode_bytes_decode_preflight( 32, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_stake_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_epoch_info_pair_decode_unsafe( fd_epoch_info_pair_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_pubkey_decode_unsafe( &self->account, ctx ); + fd_stake_decode_unsafe( &self->stake, ctx ); +} +int fd_epoch_info_pair_encode( fd_epoch_info_pair_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_pubkey_encode( &self->account, ctx ); + if( FD_UNLIKELY( err ) ) return err; + err = fd_stake_encode( &self->stake, ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +int fd_epoch_info_pair_decode_offsets( fd_epoch_info_pair_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->account_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_bincode_bytes_decode_preflight( 32, ctx ); + if( FD_UNLIKELY( err ) ) return err; + self->stake_off = (uint)( (ulong)ctx->data - (ulong)data ); + err = fd_stake_decode_preflight( ctx ); + if( FD_UNLIKELY( err ) ) return err; + return FD_BINCODE_SUCCESS; +} +void fd_epoch_info_pair_new(fd_epoch_info_pair_t * self) { + fd_memset( self, 0, sizeof(fd_epoch_info_pair_t) ); + fd_pubkey_new( &self->account ); + fd_stake_new( &self->stake ); +} +void fd_epoch_info_pair_destroy( fd_epoch_info_pair_t * self, fd_bincode_destroy_ctx_t * ctx ) { + fd_pubkey_destroy( &self->account, ctx ); + fd_stake_destroy( &self->stake, ctx ); +} + +ulong fd_epoch_info_pair_footprint( void ){ return FD_EPOCH_INFO_PAIR_FOOTPRINT; } +ulong fd_epoch_info_pair_align( void ){ return FD_EPOCH_INFO_PAIR_ALIGN; } + +void fd_epoch_info_pair_walk( void * w, fd_epoch_info_pair_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_epoch_info_pair", level++ ); + fd_pubkey_walk( w, &self->account, fun, "account", level ); + fd_stake_walk( w, &self->stake, fun, "stake", level ); + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_epoch_info_pair", level-- ); +} +ulong fd_epoch_info_pair_size( fd_epoch_info_pair_t const * self ) { + ulong size = 0; + size += fd_pubkey_size( &self->account ); + size += fd_stake_size( &self->stake ); + return size; +} + +int fd_epoch_info_decode( fd_epoch_info_t * self, fd_bincode_decode_ctx_t * ctx ) { + void const * data = ctx->data; + int err = fd_epoch_info_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + ctx->data = data; + if( !fd_is_null_alloc_virtual( ctx->valloc ) ) { + fd_epoch_info_new( self ); + } + fd_epoch_info_decode_unsafe( self, ctx ); + return FD_BINCODE_SUCCESS; +} +int fd_epoch_info_decode_preflight( fd_bincode_decode_ctx_t * ctx ) { + int err; + ulong infos_len; + err = fd_bincode_uint64_decode( &infos_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( infos_len ) { + for( ulong i=0; i < infos_len; i++ ) { + err = fd_epoch_info_pair_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + } + return FD_BINCODE_SUCCESS; +} +void fd_epoch_info_decode_unsafe( fd_epoch_info_t * self, fd_bincode_decode_ctx_t * ctx ) { + fd_bincode_uint64_decode_unsafe( &self->infos_len, ctx ); + if( self->infos_len ) { + self->infos = (fd_epoch_info_pair_t *)fd_valloc_malloc( ctx->valloc, FD_EPOCH_INFO_PAIR_ALIGN, FD_EPOCH_INFO_PAIR_FOOTPRINT*self->infos_len ); + for( ulong i=0; i < self->infos_len; i++ ) { + fd_epoch_info_pair_new( self->infos + i ); + fd_epoch_info_pair_decode_unsafe( self->infos + i, ctx ); + } + } else + self->infos = NULL; +} +int fd_epoch_info_encode( fd_epoch_info_t const * self, fd_bincode_encode_ctx_t * ctx ) { + int err; + err = fd_bincode_uint64_encode( self->infos_len, ctx ); + if( FD_UNLIKELY(err) ) return err; + if( self->infos_len ) { + for( ulong i=0; i < self->infos_len; i++ ) { + err = fd_epoch_info_pair_encode( self->infos + i, ctx ); + if( FD_UNLIKELY( err ) ) return err; + } + } + return FD_BINCODE_SUCCESS; +} +int fd_epoch_info_decode_offsets( fd_epoch_info_off_t * self, fd_bincode_decode_ctx_t * ctx ) { + uchar const * data = ctx->data; + int err; + self->infos_off = (uint)( (ulong)ctx->data - (ulong)data ); + ulong infos_len; + err = fd_bincode_uint64_decode( &infos_len, ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + if( infos_len ) { + for( ulong i=0; i < infos_len; i++ ) { + err = fd_epoch_info_pair_decode_preflight( ctx ); + if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err; + } + } + return FD_BINCODE_SUCCESS; +} +void fd_epoch_info_new(fd_epoch_info_t * self) { + fd_memset( self, 0, sizeof(fd_epoch_info_t) ); +} +void fd_epoch_info_destroy( fd_epoch_info_t * self, fd_bincode_destroy_ctx_t * ctx ) { + if( self->infos ) { + for( ulong i=0; i < self->infos_len; i++ ) + fd_epoch_info_pair_destroy( self->infos + i, ctx ); + fd_valloc_free( ctx->valloc, self->infos ); + self->infos = NULL; + } +} + +ulong fd_epoch_info_footprint( void ){ return FD_EPOCH_INFO_FOOTPRINT; } +ulong fd_epoch_info_align( void ){ return FD_EPOCH_INFO_ALIGN; } + +void fd_epoch_info_walk( void * w, fd_epoch_info_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ) { + fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_epoch_info", level++ ); + if( self->infos_len ) { + fun( w, NULL, "infos", FD_FLAMENCO_TYPE_ARR, "array", level++ ); + for( ulong i=0; i < self->infos_len; i++ ) + fd_epoch_info_pair_walk(w, self->infos + i, fun, "epoch_info_pair", level ); + fun( w, NULL, "infos", FD_FLAMENCO_TYPE_ARR_END, "array", level-- ); + } + fun( w, self, name, FD_FLAMENCO_TYPE_MAP_END, "fd_epoch_info", level-- ); +} +ulong fd_epoch_info_size( fd_epoch_info_t const * self ) { + ulong size = 0; + do { + size += sizeof(ulong); + for( ulong i=0; i < self->infos_len; i++ ) + size += fd_epoch_info_pair_size( self->infos + i ); + } while(0); + return size; +} + int fd_stake_pair_decode( fd_stake_pair_t * self, fd_bincode_decode_ctx_t * ctx ) { void const * data = ctx->data; int err = fd_stake_pair_decode_preflight( ctx ); diff --git a/src/flamenco/types/fd_types.h b/src/flamenco/types/fd_types.h index c938c57caa..4e83f0ce6b 100644 --- a/src/flamenco/types/fd_types.h +++ b/src/flamenco/types/fd_types.h @@ -284,16 +284,12 @@ typedef struct fd_rent_collector_off fd_rent_collector_off_t; #define FD_RENT_COLLECTOR_OFF_FOOTPRINT sizeof(fd_rent_collector_off_t) #define FD_RENT_COLLECTOR_OFF_ALIGN (8UL) -/* Encoded Size: Fixed (64 bytes) */ +/* Encoded Size: Fixed (32 bytes) */ struct __attribute__((aligned(8UL))) fd_stake_history_entry { ulong epoch; ulong effective; ulong activating; ulong deactivating; - ulong parent; - ulong left; - ulong right; - ulong prio; }; typedef struct fd_stake_history_entry fd_stake_history_entry_t; #define FD_STAKE_HISTORY_ENTRY_FOOTPRINT sizeof(fd_stake_history_entry_t) @@ -304,49 +300,18 @@ struct __attribute__((aligned(8UL))) fd_stake_history_entry_off { uint effective_off; uint activating_off; uint deactivating_off; - uint parent_off; - uint left_off; - uint right_off; - uint prio_off; }; typedef struct fd_stake_history_entry_off fd_stake_history_entry_off_t; #define FD_STAKE_HISTORY_ENTRY_OFF_FOOTPRINT sizeof(fd_stake_history_entry_off_t) #define FD_STAKE_HISTORY_ENTRY_OFF_ALIGN (8UL) -#define FD_STAKE_HISTORY_MIN 512 -#define POOL_NAME fd_stake_history_pool -#define POOL_T fd_stake_history_entry_t -#define POOL_NEXT parent -#include "../../util/tmpl/fd_pool.c" -static inline fd_stake_history_entry_t * -fd_stake_history_pool_alloc( fd_valloc_t valloc, ulong num ) { - if( FD_UNLIKELY( 0 == num ) ) num = 1; // prevent underflow - return fd_stake_history_pool_join( fd_stake_history_pool_new( - fd_valloc_malloc( valloc, - fd_stake_history_pool_align(), - fd_stake_history_pool_footprint( num ) ), - num ) ); -} -#define TREAP_NAME fd_stake_history_treap -#define TREAP_T fd_stake_history_entry_t -#define TREAP_QUERY_T ulong -#define TREAP_CMP(q,e) ((q == (e)->epoch) ? 0 : ((q < (e)->epoch) ? -1 : 1 ) ) -#define TREAP_LT(e0,e1) ((e0)->epoch<(e1)->epoch) -#include "../../util/tmpl/fd_treap.c" -static inline fd_stake_history_treap_t * -fd_stake_history_treap_alloc( fd_valloc_t valloc, ulong num ) { - if( FD_UNLIKELY( 0 == num ) ) num = 1; // prevent underflow - return fd_stake_history_treap_join( fd_stake_history_treap_new( - fd_valloc_malloc( valloc, - fd_stake_history_treap_align(), - fd_stake_history_treap_footprint( num ) ), - num ) ); -} /* https://github.com/firedancer-io/solana/blob/v1.17/sdk/program/src/stake_history.rs#L12-L75 */ /* Encoded Size: Dynamic */ struct __attribute__((aligned(8UL))) fd_stake_history { - fd_stake_history_entry_t * pool; - fd_stake_history_treap_t * treap; + ulong fd_stake_history_len; + ulong fd_stake_history_size; + ulong fd_stake_history_offset; + fd_stake_history_entry_t fd_stake_history[512]; }; typedef struct fd_stake_history fd_stake_history_t; #define FD_STAKE_HISTORY_FOOTPRINT sizeof(fd_stake_history_t) @@ -687,6 +652,39 @@ typedef struct fd_stake_off fd_stake_off_t; #define FD_STAKE_OFF_FOOTPRINT sizeof(fd_stake_off_t) #define FD_STAKE_OFF_ALIGN (8UL) +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_epoch_info_pair { + fd_pubkey_t account; + fd_stake_t stake; +}; +typedef struct fd_epoch_info_pair fd_epoch_info_pair_t; +#define FD_EPOCH_INFO_PAIR_FOOTPRINT sizeof(fd_epoch_info_pair_t) +#define FD_EPOCH_INFO_PAIR_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_epoch_info_pair_off { + uint account_off; + uint stake_off; +}; +typedef struct fd_epoch_info_pair_off fd_epoch_info_pair_off_t; +#define FD_EPOCH_INFO_PAIR_OFF_FOOTPRINT sizeof(fd_epoch_info_pair_off_t) +#define FD_EPOCH_INFO_PAIR_OFF_ALIGN (8UL) + +/* Encoded Size: Dynamic */ +struct __attribute__((aligned(8UL))) fd_epoch_info { + ulong infos_len; + fd_epoch_info_pair_t * infos; +}; +typedef struct fd_epoch_info fd_epoch_info_t; +#define FD_EPOCH_INFO_FOOTPRINT sizeof(fd_epoch_info_t) +#define FD_EPOCH_INFO_ALIGN (8UL) + +struct __attribute__((aligned(8UL))) fd_epoch_info_off { + uint infos_off; +}; +typedef struct fd_epoch_info_off fd_epoch_info_off_t; +#define FD_EPOCH_INFO_OFF_FOOTPRINT sizeof(fd_epoch_info_off_t) +#define FD_EPOCH_INFO_OFF_ALIGN (8UL) + /* Encoded Size: Dynamic */ struct __attribute__((aligned(8UL))) fd_stake_pair { fd_pubkey_t account; @@ -5356,6 +5354,30 @@ ulong fd_stake_size( fd_stake_t const * self ); ulong fd_stake_footprint( void ); ulong fd_stake_align( void ); +void fd_epoch_info_pair_new( fd_epoch_info_pair_t * self ); +int fd_epoch_info_pair_decode( fd_epoch_info_pair_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_epoch_info_pair_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_epoch_info_pair_decode_unsafe( fd_epoch_info_pair_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_epoch_info_pair_decode_offsets( fd_epoch_info_pair_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_epoch_info_pair_encode( fd_epoch_info_pair_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_epoch_info_pair_destroy( fd_epoch_info_pair_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_epoch_info_pair_walk( void * w, fd_epoch_info_pair_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_epoch_info_pair_size( fd_epoch_info_pair_t const * self ); +ulong fd_epoch_info_pair_footprint( void ); +ulong fd_epoch_info_pair_align( void ); + +void fd_epoch_info_new( fd_epoch_info_t * self ); +int fd_epoch_info_decode( fd_epoch_info_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_epoch_info_decode_preflight( fd_bincode_decode_ctx_t * ctx ); +void fd_epoch_info_decode_unsafe( fd_epoch_info_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_epoch_info_decode_offsets( fd_epoch_info_off_t * self, fd_bincode_decode_ctx_t * ctx ); +int fd_epoch_info_encode( fd_epoch_info_t const * self, fd_bincode_encode_ctx_t * ctx ); +void fd_epoch_info_destroy( fd_epoch_info_t * self, fd_bincode_destroy_ctx_t * ctx ); +void fd_epoch_info_walk( void * w, fd_epoch_info_t const * self, fd_types_walk_fn_t fun, const char *name, uint level ); +ulong fd_epoch_info_size( fd_epoch_info_t const * self ); +ulong fd_epoch_info_footprint( void ); +ulong fd_epoch_info_align( void ); + void fd_stake_pair_new( fd_stake_pair_t * self ); int fd_stake_pair_decode( fd_stake_pair_t * self, fd_bincode_decode_ctx_t * ctx ); int fd_stake_pair_decode_preflight( fd_bincode_decode_ctx_t * ctx ); diff --git a/src/flamenco/types/fd_types.json b/src/flamenco/types/fd_types.json index 6dc30728aa..35c22e290d 100644 --- a/src/flamenco/types/fd_types.json +++ b/src/flamenco/types/fd_types.json @@ -166,18 +166,14 @@ { "name": "epoch", "type": "ulong" }, { "name": "effective", "type": "ulong" }, { "name": "activating", "type": "ulong" }, - { "name": "deactivating", "type": "ulong" }, - { "name": "parent", "type": "ulong", "decode": false, "encode": false, "walk": false }, - { "name": "left", "type": "ulong", "decode": false, "encode": false, "walk": false }, - { "name": "right", "type": "ulong", "decode": false, "encode": false, "walk": false }, - { "name": "prio", "type": "ulong", "decode": false, "encode": false, "walk": false } + { "name": "deactivating", "type": "ulong" } ] }, { "name": "stake_history", "type": "struct", "fields": [ - { "name": "fd_stake_history", "type": "treap", "treap_t": "fd_stake_history_entry_t", "treap_query_t": "ulong", "treap_cmp": "((q == (e)->epoch) ? 0 : ((q < (e)->epoch) ? -1 : 1 ) )", "treap_lt": "((e0)->epoch<(e1)->epoch)", "min": 512, "rev": true } + { "name": "fd_stake_history", "type": "static_vector", "element": "stake_history_entry", "size": 512 } ], "comment": "https://github.com/firedancer-io/solana/blob/v1.17/sdk/program/src/stake_history.rs#L12-L75" }, @@ -315,6 +311,21 @@ ], "comment": "https://github.com/solana-labs/solana/blob/8f2c8b8388a495d2728909e30460aa40dcc5d733/sdk/program/src/stake/state.rs#L539" }, + { + "name": "epoch_info_pair", + "type": "struct", + "fields": [ + { "name": "account", "type": "pubkey" }, + { "name": "stake", "type": "stake" } + ] + }, + { + "name": "epoch_info", + "type": "struct", + "fields": [ + { "name": "infos", "type": "vector", "element":"epoch_info_pair" } + ] + }, { "name": "stake_pair", "type": "struct", diff --git a/src/flamenco/types/gen_stubs.py b/src/flamenco/types/gen_stubs.py index 4971f4e842..e992d5cbf8 100644 --- a/src/flamenco/types/gen_stubs.py +++ b/src/flamenco/types/gen_stubs.py @@ -405,7 +405,6 @@ def emitSize(self, inner): def emitWalk(self, inner): print(f'{indent} {namespace}_{self.type}_walk( w, &self->{inner}{self.name}, fun, "{self.name}", level );', file=body) - class VectorMember: def __init__(self, container, json): self.name = json["name"] @@ -584,6 +583,168 @@ def emitWalk(self, inner): print(f' fun( w, NULL, "{self.name}", FD_FLAMENCO_TYPE_ARR_END, "array", level-- );', file=body) print(' }', file=body) +class StaticVectorMember: + def __init__(self, container, json): + self.name = json["name"] + self.element = json["element"] + self.size = (json["size"] if "size" in json else None) + self.ignore_underflow = (bool(json["ignore_underflow"]) if "ignore_underflow" in json else False) + + def propogateArchival(self, nametypes): + fulltype = f'{namespace}_{self.element}' + if fulltype in nametypes: + nametypes[fulltype].propogateArchival(nametypes) + + def metaTag(self): + return "FD_ARCHIVE_META_STATIC_VECTOR" + + def isFixedSize(self): + return False + + def emitPreamble(self): + pass + + def emitPostamble(self): + pass + + def emitMember(self): + print(f' ulong {self.name}_len;', file=header) + print(f' ulong {self.name}_size;', file=header) + print(f' ulong {self.name}_offset;', file=header) + + if self.element in simpletypes: + print(f' {self.element} {self.name}[{self.size}];', file=header) + else: + print(f' {namespace}_{self.element}_t {self.name}[{self.size}];', file=header) + + def emitOffsetMember(self): + print(f' uint {self.name}_off;', file=header) + + def emitNew(self): + size = self.size + print(f' self->{self.name}_size = {self.size};', file=body) + if self.element in simpletypes: + pass + else: + print(f' for( ulong i=0; i<{size}; i++ )', file=body) + print(f' {namespace}_{self.element}_new( self->{self.name} + i );', file=body) + + + def emitDestroy(self): + size = self.size + + if self.element in simpletypes: + pass + else: + print(f' for( ulong i=0; i<{size}; i++ )', file=body) + print(f' {namespace}_{self.element}_destroy( self->{self.name} + i, ctx );', file=body) + + def emitDecodePreflight(self, archival): + atag = ('_archival' if archival else '') + print(f' ulong {self.name}_len;', file=body) + print(f' err = fd_bincode_uint64_decode( &{self.name}_len, ctx );', file=body) + print(f' if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;', file=body) + print(f' if( {self.name}_len ) {{', file=body) + el = f'{namespace}_{self.element}' + el = el.upper() + + if self.element == "uchar": + print(f' err = fd_bincode_bytes_decode_preflight( {self.name}_len, ctx );', file=body) + print(f' if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;', file=body) + + else: + print(f' for( ulong i=0; i < {self.name}_len; i++ ) {{', file=body) + + if self.element in simpletypes: + print(f' err = fd_bincode_{simpletypes[self.element]}_decode_preflight( ctx );', file=body) + else: + print(f' err = {namespace}_{self.element}_decode{atag}_preflight( ctx );', file=body) + + print(f' if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;', file=body) + print(' }', file=body) + + print(' }', file=body) + + def emitDecodeUnsafe(self, archival): + atag = ('_archival' if archival else '') + print(f' fd_bincode_uint64_decode_unsafe( &self->{self.name}_len, ctx );', file=body) + print(f' self->{self.name}_size = {self.size};', file=body) + print(f' self->{self.name}_offset = 0;', file=body) + + if self.element == "uchar": + print(f' fd_bincode_bytes_decode_unsafe( self->{self.name}, self->{self.name}_len, ctx );', file=body) + return + + print(f' for( ulong i=0; i{self.name}_len; i++ ) {{', file=body) + if self.element in simpletypes: + print(f' fd_bincode_{simpletypes[self.element]}_decode_unsafe( self->{self.name} + i, ctx );', file=body) + else: + print(f' {namespace}_{self.element}_decode{atag}_unsafe( self->{self.name} + i, ctx );', file=body) + print(' }', file=body) + + def emitEncode(self, archival): + atag = ('_archival' if archival else '') + + atag = ('_archival' if archival else '') + print(f' err = fd_bincode_uint64_encode( self->{self.name}_len, ctx );', file=body) + print(f' if( FD_UNLIKELY(err) ) return err;', file=body) + print(f' if( FD_UNLIKELY( 0 == self->{self.name}_len ) ) return FD_BINCODE_SUCCESS;', file=body) + + if self.element == "uchar": + #print(f' err = fd_bincode_bytes_encode( self->{self.name}, self->{self.name}_len, ctx );', file=body) + print(f' TODO: implement this windowed properly', file=body) + print(' if( FD_UNLIKELY( err ) ) return err;', file=body) + return + + print(f' for( ulong i=0; i{self.name}_len; i++ ) {{', file=body) + if (self.size & (self.size - 1)) == 0: + print(f' ulong idx = ( i + self->{self.name}_offset ) & ({self.size} - 1);', file=body) + else: + print(f' ulong idx = ( i + self->{self.name}_offset ) % self->{self.name}_size;', file=body) + if self.element in simpletypes: + print(f' err = fd_bincode_{simpletypes[self.element]}_encode( self->{self.name}[idx], ctx );', file=body) + else: + print(f' err = {namespace}_{self.element}_encode{atag}( self->{self.name} + idx, ctx );', file=body) + print(' if( FD_UNLIKELY( err ) ) return err;', file=body) + print(' }', file=body) + + def emitSize(self, inner): + print(' size += sizeof(ulong);', file=body) + if self.element == "uchar": + print(f' size += self->{self.name}_len;', file=body) + elif self.element in simpletypes: + print(f' size += self->{self.name}_len * sizeof({self.element});', file=body) + else: + print(f' for( ulong i=0; i{self.name}_len; i++ )', file=body) + print(f' size += {namespace}_{self.element}_size( self->{self.name} + i );', file=body) + + emitWalkMap = { + "double" : lambda n: print(f' fun( w, self->{n} + idx, "{n}", FD_FLAMENCO_TYPE_DOUBLE, "double", level );', file=body), + "long" : lambda n: print(f' fun( w, self->{n} + idx, "{n}", FD_FLAMENCO_TYPE_LONG, "long", level );', file=body), + "uint" : lambda n: print(f' fun( w, self->{n} + idx, "{n}", FD_FLAMENCO_TYPE_UINT, "uint", level );', file=body), + "uint128" : lambda n: print(f' fun( w, self->{n} + idx, "{n}", FD_FLAMENCO_TYPE_UINT128, "uint128", level );', file=body), + "ulong" : lambda n: print(f' fun( w, self->{n} + idx, "{n}", FD_FLAMENCO_TYPE_ULONG, "ulong", level );', file=body), + "ushort" : lambda n: print(f' fun( w, self->{n} + idx, "{n}", FD_FLAMENCO_TYPE_USHORT, "ushort", level );', file=body) + } + + def emitWalk(self, inner): + if self.element == "uchar": + print(f' TODO: IMPLEMENT', file=body), + return + + print(f' fun( w, NULL, "{self.name}", FD_FLAMENCO_TYPE_ARR, "{self.element}[]", level++ );', file=body) + print(f' for( ulong i=0; i{self.name}_len; i++ ) {{', file=body) + if (self.size & (self.size - 1)) == 0: + print(f' ulong idx = ( i + self->{self.name}_offset ) & ({self.size} - 1);', file=body) + else: + print(f' ulong idx = ( i + self->{self.name}_offset ) % self->{self.name}_size;', file=body) + if self.element in VectorMember.emitWalkMap: + body.write(" ") + VectorMember.emitWalkMap[self.element](self.name) + else: + print(f' {namespace}_{self.element}_walk( w, self->{self.name} + idx, fun, "{self.element}", level );', file=body) + print(' }', file=body) + print(f' fun( w, NULL, "{self.name}", FD_FLAMENCO_TYPE_ARR_END, "{self.element}[]", level-- );', file=body) class StringMember(VectorMember): def __init__(self, container, json): @@ -608,7 +769,6 @@ def emitDecodePreflight(self, archival): print(' }', file=body) - class DequeMember: def __init__(self, container, json): self.name = json["name"] @@ -1049,6 +1209,7 @@ def __init__(self, container, json): self.min = int(json["min"]) self.compact = ("modifier" in json and json["modifier"] == "compact") self.treap_prio = (json["treap_prio"] if "treap_prio" in json else None) + self.treap_optimize = (json["optimize"] if "optimize" in json else None) self.rev = json.get("rev", False) self.upsert = json.get("upsert", False) self.min_name = f"{self.name.upper()}_MIN" @@ -1094,6 +1255,8 @@ def emitPreamble(self): print(f"#define TREAP_QUERY_T {treap_query_t}", file=header) print(f"#define TREAP_CMP(q,e) {treap_cmp}", file=header) print(f"#define TREAP_LT(e0,e1) {treap_lt}", file=header) + if self.treap_optimize is not None: + print(f"#define TREAP_OPTIMIZE_ITERATION 1", file=header) if self.treap_prio is not None: print(f"#define TREAP_PRIO {self.treap_prio}", file=header) print("#include \"../../util/tmpl/fd_treap.c\"", file=header) @@ -1462,7 +1625,6 @@ def emitWalk(self, inner): print(f' {namespace}_{self.element}_walk( w, self->{self.name}, fun, "{self.name}", level );', file=body) print( ' }', file=body) - class ArrayMember: def __init__(self, container, json): self.name = json["name"] @@ -1591,8 +1753,8 @@ def emitWalk(self, inner): print(f' {namespace}_{self.element}_walk( w, self->{self.name} + i, fun, "{self.element}", level );', file=body) print(f' fun( w, NULL, "{self.name}", FD_FLAMENCO_TYPE_ARR_END, "{self.element}[]", level-- );', file=body) - memberTypeMap = { + "static_vector" : StaticVectorMember, "vector" : VectorMember, "string" : StringMember, "deque" : DequeMember, @@ -1993,7 +2155,7 @@ def __init__(self, json): self.repr = (json["repr"] if "repr" in json else "uint") self.repr_codec_stem = "uint32" self.repr_max_val = "UINT_MAX" - + if self.repr == "ulong": self.repr_codec_stem = "uint64" self.repr_max_val = "ULONG_MAX"