Skip to content

Commit 0071cf4

Browse files
rewards: cleaning up stake calculation
1 parent 239e46d commit 0071cf4

File tree

8 files changed

+170
-230
lines changed

8 files changed

+170
-230
lines changed

src/flamenco/rewards/fd_rewards.c

Lines changed: 104 additions & 78 deletions
Large diffs are not rendered by default.

src/flamenco/runtime/fd_runtime.c

Lines changed: 5 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,41 +1582,6 @@ fd_runtime_prepare_and_execute_txn( fd_banks_t * banks,
15821582
/* Epoch Boundary */
15831583
/******************************************************************************/
15841584

1585-
/* Update the epoch bank stakes cache with the delegated stake values from the slot bank cache.
1586-
The slot bank cache will have been accumulating this epoch, and now we are at an epoch boundary
1587-
we can safely update the epoch stakes cache with the latest values.
1588-
1589-
In Solana, the stakes cache is updated after every transaction
1590-
(https://github.com/solana-labs/solana/blob/c091fd3da8014c0ef83b626318018f238f506435/runtime/src/bank.rs#L7587).
1591-
As delegations have to warm up, the contents of the cache will not change inter-epoch. We can therefore update
1592-
the cache only at epoch boundaries.
1593-
1594-
https://github.com/solana-labs/solana/blob/c091fd3da8014c0ef83b626318018f238f506435/runtime/src/stakes.rs#L65 */
1595-
static void
1596-
fd_update_stake_delegations( fd_exec_slot_ctx_t * slot_ctx,
1597-
fd_epoch_info_t * temp_info ) {
1598-
1599-
fd_stake_delegations_t * stake_delegations = fd_stake_delegations_join( fd_bank_stake_delegations_locking_modify( slot_ctx->bank ) );
1600-
1601-
/* In one pass, iterate over all the new stake infos and insert the updated values into the epoch stakes cache
1602-
This assumes that there is enough memory pre-allocated for the stakes cache. */
1603-
for( ulong idx=temp_info->stake_infos_new_keys_start_idx; idx<temp_info->stake_infos_len; idx++ ) {
1604-
// Fetch and store the delegation associated with this stake account
1605-
fd_stake_delegations_update(
1606-
stake_delegations,
1607-
&temp_info->stake_infos[idx].account,
1608-
&temp_info->stake_infos[idx].stake.delegation.voter_pubkey,
1609-
temp_info->stake_infos[idx].stake.delegation.stake,
1610-
temp_info->stake_infos[idx].stake.delegation.activation_epoch,
1611-
temp_info->stake_infos[idx].stake.delegation.deactivation_epoch,
1612-
temp_info->stake_infos[idx].stake.credits_observed,
1613-
temp_info->stake_infos[idx].stake.delegation.warmup_cooldown_rate
1614-
);
1615-
}
1616-
1617-
fd_bank_stake_delegations_end_locking_modify( slot_ctx->bank );
1618-
}
1619-
16201585
/* Replace the stakes in T-2 (epoch_stakes) by the stakes at T-1 (next_epoch_stakes) */
16211586
static void
16221587
fd_update_epoch_stakes( fd_exec_slot_ctx_t * slot_ctx ) {
@@ -2249,12 +2214,11 @@ fd_runtime_process_new_epoch( fd_exec_slot_ctx_t * slot_ctx,
22492214
}
22502215

22512216
/* Updates stake history sysvar accumulated values. */
2252-
fd_stakes_activate_epoch( slot_ctx,
2253-
new_rate_activation_epoch,
2254-
&temp_info,
2255-
runtime_spad );
2256-
2257-
fd_update_stake_delegations( slot_ctx, &temp_info );
2217+
fd_stakes_activate_epoch(
2218+
slot_ctx,
2219+
new_rate_activation_epoch,
2220+
&temp_info,
2221+
runtime_spad );
22582222

22592223
/* Refresh vote accounts in stakes cache using updated stake weights, and merges slot bank vote accounts with the epoch bank vote accounts.
22602224
https://github.com/anza-xyz/agave/blob/v2.1.6/runtime/src/stakes.rs#L363-L370 */

src/flamenco/stakes/fd_stakes.c

Lines changed: 61 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "../runtime/context/fd_exec_slot_ctx.h"
55
#include "../runtime/program/fd_stake_program.h"
66
#include "../runtime/sysvar/fd_sysvar_stake_history.h"
7+
#include "fd_stake_delegations.h"
78

89
ulong
910
fd_stake_weights_by_node( fd_vote_accounts_global_t const * accs,
@@ -73,18 +74,14 @@ deserialize_and_update_vote_account( fd_exec_slot_ctx_t *
7374
}
7475

7576
static void
76-
compute_stake_delegations(
77-
fd_epoch_info_t * temp_info,
78-
ulong const epoch,
79-
fd_stake_history_t const * history,
80-
ulong * new_rate_activation_epoch,
81-
fd_stake_weight_t_mapnode_t * delegation_pool,
82-
fd_stake_weight_t_mapnode_t * delegation_root,
83-
ulong vote_states_pool_sz,
84-
fd_spad_t * spad,
85-
ulong end_idx
86-
) {
87-
fd_epoch_info_pair_t const * stake_infos = temp_info->stake_infos;
77+
compute_stake_delegations( fd_bank_t * bank,
78+
ulong const epoch,
79+
fd_stake_history_t const * history,
80+
ulong * new_rate_activation_epoch,
81+
fd_stake_weight_t_mapnode_t * delegation_pool,
82+
fd_stake_weight_t_mapnode_t * delegation_root,
83+
ulong vote_states_pool_sz,
84+
fd_spad_t * spad ) {
8885

8986
FD_SPAD_FRAME_BEGIN( spad ) {
9087

@@ -93,22 +90,43 @@ compute_stake_delegations(
9390
fd_stake_weight_t_mapnode_t * temp_pool = fd_stake_weight_t_map_join( fd_stake_weight_t_map_new( mem, vote_states_pool_sz ) );
9491
fd_stake_weight_t_mapnode_t * temp_root = NULL;
9592

93+
fd_stake_delegations_t const * stake_delegations = fd_bank_stake_delegations_locking_query( bank );
94+
if( FD_UNLIKELY( !stake_delegations ) ) {
95+
FD_LOG_CRIT(( "stake_delegations is NULL" ));
96+
}
97+
fd_stake_delegation_map_t * stake_delegation_map = fd_stake_delegations_get_map( stake_delegations );
98+
fd_stake_delegation_t * stake_delegation_pool = fd_stake_delegations_get_pool( stake_delegations );
99+
96100
fd_stake_weight_t_mapnode_t temp;
97-
for( ulong i=0UL; i<end_idx; i++ ) {
98-
fd_delegation_t const * delegation = &stake_infos[i].stake.delegation;
99-
temp.elem.key = delegation->voter_pubkey;
101+
102+
for( fd_stake_delegation_map_iter_t iter = fd_stake_delegation_map_iter_init( stake_delegation_map, stake_delegation_pool );
103+
!fd_stake_delegation_map_iter_done( iter, stake_delegation_map, stake_delegation_pool );
104+
iter = fd_stake_delegation_map_iter_next( iter, stake_delegation_map, stake_delegation_pool ) ) {
105+
106+
107+
fd_stake_delegation_t const * stake_delegation = fd_stake_delegation_map_iter_ele_const( iter, stake_delegation_map, stake_delegation_pool );
108+
109+
temp.elem.key = stake_delegation->vote_account;
100110

101111
// Skip any delegations that are not in the delegation pool
102112
fd_stake_weight_t_mapnode_t * delegation_entry = fd_stake_weight_t_map_find( delegation_pool, delegation_root, &temp );
103113
if( FD_UNLIKELY( delegation_entry==NULL ) ) {
104114
continue;
105115
}
106116

107-
fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, epoch, history, new_rate_activation_epoch );
117+
fd_delegation_t delegation = {
118+
.voter_pubkey = stake_delegation->vote_account,
119+
.stake = stake_delegation->stake,
120+
.deactivation_epoch = stake_delegation->deactivation_epoch,
121+
.activation_epoch = stake_delegation->activation_epoch,
122+
.warmup_cooldown_rate = stake_delegation->warmup_cooldown_rate,
123+
};
124+
125+
fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( &delegation, epoch, history, new_rate_activation_epoch );
108126
delegation_entry = fd_stake_weight_t_map_find( temp_pool, temp_root, &temp );
109127
if( FD_UNLIKELY( delegation_entry==NULL ) ) {
110128
delegation_entry = fd_stake_weight_t_map_acquire( temp_pool );
111-
delegation_entry->elem.key = delegation->voter_pubkey;
129+
delegation_entry->elem.key = stake_delegation->vote_account;
112130
delegation_entry->elem.stake = new_entry.effective;
113131
fd_stake_weight_t_map_insert( temp_pool, &temp_root, delegation_entry );
114132
} else {
@@ -124,6 +142,8 @@ compute_stake_delegations(
124142
output_delegation_node->elem.stake += elem->elem.stake;
125143
}
126144

145+
fd_bank_stake_delegations_end_locking_query( bank );
146+
127147
} FD_SPAD_FRAME_END;
128148

129149
}
@@ -189,16 +209,14 @@ fd_populate_vote_accounts( fd_exec_slot_ctx_t * slot_ctx,
189209
fd_bank_vote_account_keys_end_locking_modify( slot_ctx->bank );
190210

191211
compute_stake_delegations(
192-
temp_info,
212+
slot_ctx->bank,
193213
fd_bank_epoch_get( slot_ctx->bank ),
194214
history,
195215
new_rate_activation_epoch,
196216
pool,
197217
root,
198218
vote_states_pool_sz,
199-
runtime_spad,
200-
temp_info->stake_infos_len
201-
);
219+
runtime_spad );
202220

203221
// Iterate over each vote account in the epoch stakes cache and populate the new vote accounts pool
204222
/* NOTE: we use epoch_bank->next_epoch_stakes because Agave indexes their epoch stakes cache by leader schedule epoch.
@@ -308,16 +326,14 @@ fd_refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx,
308326
}
309327

310328
compute_stake_delegations(
311-
temp_info,
329+
slot_ctx->bank,
312330
fd_bank_epoch_get( slot_ctx->bank ),
313331
history,
314332
new_rate_activation_epoch,
315333
pool,
316334
root,
317335
vote_states_pool_sz,
318-
runtime_spad,
319-
temp_info->stake_infos_len
320-
);
336+
runtime_spad );
321337

322338
// Iterate over each vote account in the epoch stakes cache and populate the new vote accounts pool
323339
ulong total_epoch_stake = 0UL;
@@ -403,13 +419,11 @@ fd_refresh_vote_accounts( fd_exec_slot_ctx_t * slot_ctx,
403419
}
404420

405421
static void
406-
accumulate_stake_cache_delegations(
407-
fd_stake_delegations_t * stake_delegations,
408-
fd_stake_history_t const * history,
409-
ulong * new_rate_activation_epoch,
410-
fd_stake_history_entry_t * accumulator,
411-
fd_epoch_info_t * temp_info,
412-
ulong epoch ) {
422+
accumulate_stake_cache_delegations( fd_stake_delegations_t * stake_delegations,
423+
fd_stake_history_t const * history,
424+
ulong * new_rate_activation_epoch,
425+
fd_stake_history_entry_t * accumulator,
426+
ulong epoch ) {
413427

414428
fd_stake_delegation_t * pool = fd_stake_delegations_get_pool( stake_delegations );
415429
fd_stake_delegation_map_t * map = fd_stake_delegations_get_map( stake_delegations );
@@ -423,19 +437,19 @@ accumulate_stake_cache_delegations(
423437
iter = fd_stake_delegation_map_iter_next( iter, map, pool ) ) {
424438
fd_stake_delegation_t const * stake_delegation = fd_stake_delegation_map_iter_ele_const( iter, map, pool );
425439

426-
ulong delegation_idx = temp_info->stake_infos_len++;
427-
428-
temp_info->stake_infos[delegation_idx].stake.credits_observed = stake_delegation->credits_observed;
429-
temp_info->stake_infos[delegation_idx].account = stake_delegation->stake_account;
430-
temp_info->stake_infos[delegation_idx].stake.delegation.voter_pubkey = stake_delegation->vote_account;
431-
temp_info->stake_infos[delegation_idx].stake.delegation.stake = stake_delegation->stake;
432-
temp_info->stake_infos[delegation_idx].stake.delegation.activation_epoch = stake_delegation->activation_epoch;
433-
temp_info->stake_infos[delegation_idx].stake.delegation.deactivation_epoch = stake_delegation->deactivation_epoch;
434-
temp_info->stake_infos[delegation_idx].stake.delegation.warmup_cooldown_rate = stake_delegation->warmup_cooldown_rate;
435-
436-
fd_delegation_t * delegation = &temp_info->stake_infos[delegation_idx].stake.delegation;
437-
438-
fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating( delegation, epoch, history, new_rate_activation_epoch );
440+
fd_delegation_t delegation = {
441+
.voter_pubkey = stake_delegation->vote_account,
442+
.stake = stake_delegation->stake,
443+
.activation_epoch = stake_delegation->activation_epoch,
444+
.deactivation_epoch = stake_delegation->deactivation_epoch,
445+
.warmup_cooldown_rate = stake_delegation->warmup_cooldown_rate,
446+
};
447+
448+
fd_stake_history_entry_t new_entry = fd_stake_activating_and_deactivating(
449+
&delegation,
450+
epoch,
451+
history,
452+
new_rate_activation_epoch );
439453
effective += new_entry.effective;
440454
activating += new_entry.activating;
441455
deactivating += new_entry.deactivating;
@@ -456,7 +470,6 @@ fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx,
456470
fd_stake_history_t const * history,
457471
ulong * new_rate_activation_epoch,
458472
fd_stake_history_entry_t * accumulator,
459-
fd_epoch_info_t * temp_info,
460473
fd_spad_t * runtime_spad ) {
461474

462475
FD_SPAD_FRAME_BEGIN( runtime_spad ) {
@@ -468,9 +481,7 @@ fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx,
468481
history,
469482
new_rate_activation_epoch,
470483
accumulator,
471-
temp_info,
472-
epoch
473-
);
484+
epoch );
474485

475486
} FD_SPAD_FRAME_END;
476487
}
@@ -482,6 +493,7 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx,
482493
fd_epoch_info_t * temp_info,
483494
fd_spad_t * runtime_spad ) {
484495

496+
(void)temp_info;
485497
fd_stake_delegations_t * stake_delegations = fd_stake_delegations_join( (void*)fd_bank_stake_delegations_locking_modify( slot_ctx->bank ) );
486498

487499
/* Current stake delegations: list of all current delegations in stake_delegations
@@ -492,12 +504,6 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx,
492504
fd_stake_history_t const * history = fd_sysvar_stake_history_read( slot_ctx->funk, slot_ctx->funk_txn, runtime_spad );
493505
if( FD_UNLIKELY( !history ) ) FD_LOG_ERR(( "StakeHistory sysvar is missing from sysvar cache" ));
494506

495-
ulong stake_delegations_size = fd_stake_delegations_cnt( stake_delegations );
496-
497-
temp_info->stake_infos_len = 0UL;
498-
temp_info->stake_infos = (fd_epoch_info_pair_t *)fd_spad_alloc( runtime_spad, FD_EPOCH_INFO_PAIR_ALIGN, sizeof(fd_epoch_info_pair_t)*stake_delegations_size );
499-
fd_memset( temp_info->stake_infos, 0, sizeof(fd_epoch_info_pair_t)*stake_delegations_size );
500-
501507
fd_stake_history_entry_t accumulator = {
502508
.effective = 0UL,
503509
.activating = 0UL,
@@ -511,7 +517,6 @@ fd_stakes_activate_epoch( fd_exec_slot_ctx_t * slot_ctx,
511517
history,
512518
new_rate_activation_epoch,
513519
&accumulator,
514-
temp_info,
515520
runtime_spad );
516521

517522
/* https://github.com/anza-xyz/agave/blob/v2.1.6/runtime/src/stakes.rs#L359 */

src/flamenco/stakes/fd_stakes.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ fd_accumulate_stake_infos( fd_exec_slot_ctx_t const * slot_ctx,
7070
fd_stake_history_t const * history,
7171
ulong * new_rate_activation_epoch,
7272
fd_stake_history_entry_t * accumulator,
73-
fd_epoch_info_t * temp_info,
7473
fd_spad_t * runtime_spad );
7574

7675
/* fd_store_stake_delegation is used to update fd_stake_delegations_t

src/flamenco/types/fd_fuzz_types.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3941,17 +3941,6 @@ void *fd_epoch_info_generate( void *mem, void **alloc_mem, fd_rng_t * rng ) {
39413941
fd_epoch_info_t *self = (fd_epoch_info_t *) mem;
39423942
*alloc_mem = (uchar *) *alloc_mem + sizeof(fd_epoch_info_t);
39433943
fd_epoch_info_new(mem);
3944-
self->stake_infos_len = fd_rng_ulong( rng ) % 8;
3945-
if( self->stake_infos_len ) {
3946-
self->stake_infos = (fd_epoch_info_pair_t *) *alloc_mem;
3947-
*alloc_mem = (uchar *) *alloc_mem + sizeof(fd_epoch_info_pair_t)*self->stake_infos_len;
3948-
for( ulong i=0; i < self->stake_infos_len; i++ ) {
3949-
fd_epoch_info_pair_new( self->stake_infos + i );
3950-
fd_epoch_info_pair_generate( self->stake_infos + i, alloc_mem, rng );
3951-
}
3952-
} else {
3953-
self->stake_infos = NULL;
3954-
}
39553944
ulong vote_states_len = fd_rng_ulong( rng ) % 8;
39563945
self->vote_states_pool = fd_vote_info_pair_t_map_join_new( alloc_mem, vote_states_len );
39573946
self->vote_states_root = NULL;

src/flamenco/types/fd_types.c

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -25187,14 +25187,6 @@ ulong fd_vote_info_pair_size( fd_vote_info_pair_t const * self ) {
2518725187

2518825188
int fd_epoch_info_encode( fd_epoch_info_t const * self, fd_bincode_encode_ctx_t * ctx ) {
2518925189
int err;
25190-
err = fd_bincode_uint64_encode( self->stake_infos_len, ctx );
25191-
if( FD_UNLIKELY(err) ) return err;
25192-
if( self->stake_infos_len ) {
25193-
for( ulong i=0; i < self->stake_infos_len; i++ ) {
25194-
err = fd_epoch_info_pair_encode( self->stake_infos + i, ctx );
25195-
if( FD_UNLIKELY( err ) ) return err;
25196-
}
25197-
}
2519825190
if( self->vote_states_root ) {
2519925191
ulong vote_states_len = fd_vote_info_pair_t_map_size( self->vote_states_pool, self->vote_states_root );
2520025192
err = fd_bincode_uint64_encode( vote_states_len, ctx );
@@ -25215,16 +25207,6 @@ int fd_epoch_info_encode( fd_epoch_info_t const * self, fd_bincode_encode_ctx_t
2521525207
static int fd_epoch_info_decode_footprint_inner( fd_bincode_decode_ctx_t * ctx, ulong * total_sz ) {
2521625208
if( ctx->data>=ctx->dataend ) { return FD_BINCODE_ERR_OVERFLOW; };
2521725209
int err = 0;
25218-
ulong stake_infos_len;
25219-
err = fd_bincode_uint64_decode( &stake_infos_len, ctx );
25220-
if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
25221-
if( stake_infos_len ) {
25222-
*total_sz += FD_EPOCH_INFO_PAIR_ALIGN + sizeof(fd_epoch_info_pair_t)*stake_infos_len;
25223-
for( ulong i=0; i < stake_infos_len; i++ ) {
25224-
err = fd_epoch_info_pair_decode_footprint_inner( ctx, total_sz );
25225-
if( FD_UNLIKELY( err!=FD_BINCODE_SUCCESS ) ) return err;
25226-
}
25227-
}
2522825210
ulong vote_states_len = 0UL;
2522925211
err = fd_bincode_uint64_decode( &vote_states_len, ctx );
2523025212
ulong vote_states_cnt = !!vote_states_len ? vote_states_len : 1;
@@ -25248,17 +25230,6 @@ int fd_epoch_info_decode_footprint( fd_bincode_decode_ctx_t * ctx, ulong * total
2524825230
}
2524925231
static void fd_epoch_info_decode_inner( void * struct_mem, void * * alloc_mem, fd_bincode_decode_ctx_t * ctx ) {
2525025232
fd_epoch_info_t * self = (fd_epoch_info_t *)struct_mem;
25251-
fd_bincode_uint64_decode_unsafe( &self->stake_infos_len, ctx );
25252-
if( self->stake_infos_len ) {
25253-
*alloc_mem = (void*)fd_ulong_align_up( (ulong)(*alloc_mem), FD_EPOCH_INFO_PAIR_ALIGN );
25254-
self->stake_infos = *alloc_mem;
25255-
*alloc_mem = (uchar *)(*alloc_mem) + sizeof(fd_epoch_info_pair_t)*self->stake_infos_len;
25256-
for( ulong i=0; i < self->stake_infos_len; i++ ) {
25257-
fd_epoch_info_pair_new( self->stake_infos + i );
25258-
fd_epoch_info_pair_decode_inner( self->stake_infos + i, alloc_mem, ctx );
25259-
}
25260-
} else
25261-
self->stake_infos = NULL;
2526225233
ulong vote_states_len;
2526325234
fd_bincode_uint64_decode_unsafe( &vote_states_len, ctx );
2526425235
self->vote_states_pool = fd_vote_info_pair_t_map_join_new( alloc_mem, vote_states_len );
@@ -25289,12 +25260,6 @@ void fd_epoch_info_new(fd_epoch_info_t * self) {
2528925260
void fd_epoch_info_walk( void * w, fd_epoch_info_t const * self, fd_types_walk_fn_t fun, const char *name, uint level, uint varint ) {
2529025261
(void) varint;
2529125262
fun( w, self, name, FD_FLAMENCO_TYPE_MAP, "fd_epoch_info", level++, 0 );
25292-
if( self->stake_infos_len ) {
25293-
fun( w, NULL, "stake_infos", FD_FLAMENCO_TYPE_ARR, "array", level++, 0 );
25294-
for( ulong i=0; i < self->stake_infos_len; i++ )
25295-
fd_epoch_info_pair_walk(w, self->stake_infos + i, fun, "epoch_info_pair", level, 0 );
25296-
fun( w, NULL, "stake_infos", FD_FLAMENCO_TYPE_ARR_END, "array", level--, 0 );
25297-
}
2529825263
if( self->vote_states_root ) {
2529925264
for( fd_vote_info_pair_t_mapnode_t * n = fd_vote_info_pair_t_map_minimum(self->vote_states_pool, self->vote_states_root ); n; n = fd_vote_info_pair_t_map_successor( self->vote_states_pool, n ) ) {
2530025265
fd_vote_info_pair_walk(w, &n->elem, fun, "vote_states", level, 0 );
@@ -25305,11 +25270,6 @@ void fd_epoch_info_walk( void * w, fd_epoch_info_t const * self, fd_types_walk_f
2530525270
}
2530625271
ulong fd_epoch_info_size( fd_epoch_info_t const * self ) {
2530725272
ulong size = 0;
25308-
do {
25309-
size += sizeof(ulong);
25310-
for( ulong i=0; i < self->stake_infos_len; i++ )
25311-
size += fd_epoch_info_pair_size( self->stake_infos + i );
25312-
} while(0);
2531325273
if( self->vote_states_root ) {
2531425274
size += sizeof(ulong);
2531525275
ulong max = fd_vote_info_pair_t_map_max( self->vote_states_pool );

0 commit comments

Comments
 (0)