Line data Source code
1 : #include "fd_stake_delegations.h"
2 : #include "../accdb/fd_accdb_pipe.h"
3 : #include "fd_stakes.h"
4 :
5 : #define POOL_NAME root_pool
6 792 : #define POOL_T fd_stake_delegation_t
7 799050 : #define POOL_NEXT next_
8 : #define POOL_IDX_T uint
9 : #include "../../util/tmpl/fd_pool.c"
10 :
11 : #define MAP_NAME root_map
12 : #define MAP_KEY_T fd_pubkey_t
13 : #define MAP_ELE_T fd_stake_delegation_t
14 105 : #define MAP_KEY stake_account
15 402 : #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
16 591 : #define MAP_KEY_HASH(key,seed) (fd_funk_rec_key_hash1( key->uc, seed ))
17 468 : #define MAP_NEXT next_
18 1788 : #define MAP_IDX_T uint
19 : #include "../../util/tmpl/fd_map_chain.c"
20 :
21 : #define POOL_NAME delta_pool
22 792 : #define POOL_T fd_stake_delegation_t
23 799107 : #define POOL_NEXT next_
24 : #define POOL_IDX_T uint
25 : #include "../../util/tmpl/fd_pool.c"
26 :
27 : #define DLIST_NAME fork_dlist
28 : #define DLIST_ELE_T fd_stake_delegation_t
29 132 : #define DLIST_PREV prev_
30 621 : #define DLIST_NEXT next_
31 : #define DLIST_IDX_T uint
32 : #include "../../util/tmpl/fd_dlist.c"
33 :
34 : struct fork_pool_ele { ushort next; };
35 : typedef struct fork_pool_ele fork_pool_ele_t;
36 :
37 : #define POOL_NAME fork_pool
38 792 : #define POOL_T fork_pool_ele_t
39 : #define POOL_IDX_T ushort
40 : #include "../../util/tmpl/fd_pool.c"
41 :
42 : /* Internal getters for base map + pool */
43 :
44 : static inline fd_stake_delegation_t *
45 669 : get_root_pool( fd_stake_delegations_t const * stake_delegations ) {
46 669 : return fd_type_pun( (uchar *)stake_delegations + stake_delegations->pool_offset_ );
47 669 : }
48 :
49 : static inline root_map_t *
50 600 : get_root_map( fd_stake_delegations_t const * stake_delegations ) {
51 600 : return fd_type_pun( (uchar *)stake_delegations + stake_delegations->map_offset_ );
52 600 : }
53 :
54 : /* Internal getters for delta pool + fork structures */
55 :
56 : static inline fd_stake_delegation_t *
57 909 : get_delta_pool( fd_stake_delegations_t const * stake_delegations ) {
58 909 : return fd_type_pun( (uchar *)stake_delegations + stake_delegations->delta_pool_offset_ );
59 909 : }
60 :
61 : static inline fork_pool_ele_t *
62 894 : get_fork_pool( fd_stake_delegations_t const * stake_delegations ) {
63 894 : return fd_type_pun( (uchar *)stake_delegations + stake_delegations->fork_pool_offset_ );
64 894 : }
65 :
66 : static inline fork_dlist_t *
67 : get_fork_dlist( fd_stake_delegations_t const * stake_delegations,
68 687 : ushort fork_idx ) {
69 687 : return fd_type_pun( (uchar *)stake_delegations + stake_delegations->dlist_offsets_[ fork_idx ] );
70 687 : }
71 :
72 : ulong
73 12192 : fd_stake_delegations_align( void ) {
74 12192 : return FD_STAKE_DELEGATIONS_ALIGN;
75 12192 : }
76 :
77 : ulong
78 : fd_stake_delegations_footprint( ulong max_stake_accounts,
79 : ulong expected_stake_accounts,
80 1965 : ulong max_live_slots ) {
81 :
82 1965 : ulong map_chain_cnt = root_map_chain_cnt_est( expected_stake_accounts );
83 :
84 1965 : ulong l = FD_LAYOUT_INIT;
85 1965 : l = FD_LAYOUT_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
86 1965 : l = FD_LAYOUT_APPEND( l, root_pool_align(), root_pool_footprint( max_stake_accounts ) );
87 1965 : l = FD_LAYOUT_APPEND( l, root_map_align(), root_map_footprint( map_chain_cnt ) );
88 1965 : l = FD_LAYOUT_APPEND( l, delta_pool_align(), delta_pool_footprint( max_stake_accounts ) );
89 1965 : l = FD_LAYOUT_APPEND( l, fork_pool_align(), fork_pool_footprint( max_live_slots ) );
90 5901 : for( ulong i=0UL; i<max_live_slots; i++ ) {
91 3936 : l = FD_LAYOUT_APPEND( l, fork_dlist_align(), fork_dlist_footprint() );
92 3936 : }
93 :
94 1965 : return FD_LAYOUT_FINI( l, fd_stake_delegations_align() );
95 1965 : }
96 :
97 : void *
98 : fd_stake_delegations_new( void * mem,
99 : ulong seed,
100 : ulong max_stake_accounts,
101 : ulong expected_stake_accounts,
102 402 : ulong max_live_slots ) {
103 402 : if( FD_UNLIKELY( !mem ) ) {
104 3 : FD_LOG_WARNING(( "NULL mem" ));
105 3 : return NULL;
106 3 : }
107 :
108 399 : if( FD_UNLIKELY( !max_stake_accounts ) ) {
109 3 : FD_LOG_WARNING(( "max_stake_accounts is 0" ));
110 3 : return NULL;
111 3 : }
112 :
113 396 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_stake_delegations_align() ) ) ) {
114 0 : FD_LOG_WARNING(( "misaligned mem" ));
115 0 : return NULL;
116 0 : }
117 :
118 396 : if( FD_UNLIKELY( max_live_slots>FD_STAKE_DELEGATIONS_FORK_MAX ) ) {
119 0 : FD_LOG_WARNING(( "max_live_slots is too large" ));
120 0 : return NULL;
121 0 : }
122 :
123 396 : ulong map_chain_cnt = root_map_chain_cnt_est( expected_stake_accounts );
124 :
125 396 : FD_SCRATCH_ALLOC_INIT( l, mem );
126 396 : fd_stake_delegations_t * stake_delegations = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
127 396 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, root_pool_align(), root_pool_footprint( max_stake_accounts ) );
128 396 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, root_map_align(), root_map_footprint( map_chain_cnt ) );
129 396 : void * delta_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, delta_pool_align(), delta_pool_footprint( max_stake_accounts ) );
130 396 : void * fork_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fork_pool_align(), fork_pool_footprint( max_live_slots ) );
131 1260 : for( ushort i=0; i<(ushort)max_live_slots; i++ ) {
132 864 : void * fork_dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, fork_dlist_align(), fork_dlist_footprint() );
133 0 : fork_dlist_t * dlist = fork_dlist_join( fork_dlist_new( fork_dlist_mem ) );
134 864 : if( FD_UNLIKELY( !dlist ) ) {
135 0 : FD_LOG_WARNING(( "Failed to create fork dlist" ));
136 0 : return NULL;
137 0 : }
138 864 : stake_delegations->dlist_offsets_[ i ] = (ulong)dlist - (ulong)mem;
139 864 : }
140 :
141 396 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_stake_delegations_align() )!=(ulong)mem+fd_stake_delegations_footprint( max_stake_accounts, expected_stake_accounts, max_live_slots ) ) ) {
142 0 : FD_LOG_WARNING(( "fd_stake_delegations_new: bad layout" ));
143 0 : return NULL;
144 0 : }
145 :
146 396 : fd_stake_delegation_t * root_pool = root_pool_join( root_pool_new( pool_mem, max_stake_accounts ) );
147 396 : if( FD_UNLIKELY( !root_pool ) ) {
148 0 : FD_LOG_WARNING(( "Failed to create stake delegations pool" ));
149 0 : return NULL;
150 0 : }
151 :
152 396 : root_map_t * root_map = root_map_join( root_map_new( map_mem, map_chain_cnt, seed ) );
153 396 : if( FD_UNLIKELY( !root_map ) ) {
154 0 : FD_LOG_WARNING(( "Failed to create stake delegations map" ));
155 0 : return NULL;
156 0 : }
157 :
158 396 : fd_stake_delegation_t * delta_pool = delta_pool_join( delta_pool_new( delta_pool_mem, max_stake_accounts ) );
159 396 : if( FD_UNLIKELY( !delta_pool ) ) {
160 0 : FD_LOG_WARNING(( "Failed to create stake delegation delta pool" ));
161 0 : return NULL;
162 0 : }
163 :
164 396 : fork_pool_ele_t * fork_pool = fork_pool_join( fork_pool_new( fork_pool_mem, max_live_slots ) );
165 396 : if( FD_UNLIKELY( !fork_pool ) ) {
166 0 : FD_LOG_WARNING(( "Failed to create fork pool" ));
167 0 : return NULL;
168 0 : }
169 :
170 396 : stake_delegations->max_stake_accounts_ = max_stake_accounts;
171 396 : stake_delegations->expected_stake_accounts_ = expected_stake_accounts;
172 396 : stake_delegations->pool_offset_ = (ulong)root_pool - (ulong)mem;
173 396 : stake_delegations->map_offset_ = (ulong)root_map - (ulong)mem;
174 396 : stake_delegations->delta_pool_offset_ = (ulong)delta_pool - (ulong)mem;
175 396 : stake_delegations->fork_pool_offset_ = (ulong)fork_pool - (ulong)mem;
176 :
177 396 : stake_delegations->effective_stake = 0UL;
178 396 : stake_delegations->activating_stake = 0UL;
179 396 : stake_delegations->deactivating_stake = 0UL;
180 :
181 396 : fd_rwlock_new( &stake_delegations->delta_lock );
182 :
183 396 : FD_COMPILER_MFENCE();
184 396 : FD_VOLATILE( stake_delegations->magic ) = FD_STAKE_DELEGATIONS_MAGIC;
185 396 : FD_COMPILER_MFENCE();
186 :
187 396 : return mem;
188 396 : }
189 :
190 : fd_stake_delegations_t *
191 402 : fd_stake_delegations_join( void * mem ) {
192 402 : if( FD_UNLIKELY( !mem ) ) {
193 3 : FD_LOG_WARNING(( "NULL mem" ));
194 3 : return NULL;
195 3 : }
196 :
197 399 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_stake_delegations_align() ) ) ) {
198 0 : FD_LOG_WARNING(( "misaligned mem" ));
199 0 : return NULL;
200 0 : }
201 :
202 399 : fd_stake_delegations_t * stake_delegations = (fd_stake_delegations_t *)mem;
203 :
204 399 : if( FD_UNLIKELY( stake_delegations->magic!=FD_STAKE_DELEGATIONS_MAGIC ) ) {
205 3 : FD_LOG_WARNING(( "Invalid stake delegations magic" ));
206 3 : return NULL;
207 3 : }
208 :
209 396 : return stake_delegations;
210 399 : }
211 :
212 : void
213 3 : fd_stake_delegations_init( fd_stake_delegations_t * stake_delegations ) {
214 3 : root_map_t * map = get_root_map( stake_delegations );
215 3 : fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
216 3 : root_pool_reset( pool );
217 3 : root_map_reset( map );
218 3 : }
219 :
220 : fd_stake_delegation_t const *
221 : fd_stake_delegation_root_query( fd_stake_delegations_t const * stake_delegations,
222 30 : fd_pubkey_t const * stake_account ) {
223 30 : fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
224 30 : root_map_t * map = get_root_map( stake_delegations );
225 :
226 30 : return root_map_ele_query_const( map, stake_account, NULL, pool );
227 30 : }
228 :
229 : void
230 : fd_stake_delegations_root_update( fd_stake_delegations_t * stake_delegations,
231 : fd_pubkey_t const * stake_account,
232 : fd_pubkey_t const * vote_account,
233 : ulong stake,
234 : ulong activation_epoch,
235 : ulong deactivation_epoch,
236 : ulong credits_observed,
237 54 : double warmup_cooldown_rate ) {
238 54 : fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
239 54 : root_map_t * map = get_root_map( stake_delegations );
240 :
241 54 : fd_stake_delegation_t * stake_delegation = root_map_ele_query( map, stake_account, NULL, pool );
242 54 : if( !stake_delegation ) {
243 39 : FD_CRIT( root_pool_free( pool ), "no free stake delegations in pool" );
244 39 : stake_delegation = root_pool_ele_acquire( pool );
245 39 : stake_delegation->stake_account = *stake_account;
246 39 : FD_CRIT( root_map_ele_insert( map, stake_delegation, pool ), "unable to insert stake delegation into map" );
247 39 : }
248 :
249 54 : stake_delegation->vote_account = *vote_account;
250 54 : stake_delegation->stake = stake;
251 54 : stake_delegation->activation_epoch = (ushort)fd_ulong_min( activation_epoch, USHORT_MAX );
252 54 : stake_delegation->deactivation_epoch = (ushort)fd_ulong_min( deactivation_epoch, USHORT_MAX );
253 54 : stake_delegation->credits_observed = credits_observed;
254 54 : stake_delegation->warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_enum( warmup_cooldown_rate );
255 54 : stake_delegation->dne_in_root = 0;
256 54 : stake_delegation->delta_idx = UINT_MAX;
257 54 : }
258 :
259 : static inline void
260 : fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations,
261 3 : fd_pubkey_t const * stake_account ) {
262 3 : fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
263 3 : root_map_t * map = get_root_map( stake_delegations );
264 :
265 3 : ulong delegation_idx = root_map_idx_query( map, stake_account, UINT_MAX, pool );
266 3 : if( FD_UNLIKELY( delegation_idx==UINT_MAX ) ) return;
267 :
268 3 : root_map_idx_remove( map, stake_account, delegation_idx, pool );
269 3 : root_pool_idx_release( pool, delegation_idx );
270 3 : }
271 :
272 : #if FD_HAS_DOUBLE
273 :
274 : void
275 : fd_stake_delegations_refresh( fd_stake_delegations_t * stake_delegations,
276 : ulong epoch,
277 : fd_stake_history_t const * stake_history,
278 : ulong * warmup_cooldown_rate_epoch,
279 : fd_accdb_user_t * accdb,
280 0 : fd_funk_txn_xid_t const * xid ) {
281 :
282 0 : stake_delegations->effective_stake = 0UL;
283 0 : stake_delegations->activating_stake = 0UL;
284 0 : stake_delegations->deactivating_stake = 0UL;
285 :
286 0 : root_map_t * map = get_root_map( stake_delegations );
287 0 : fd_stake_delegation_t * pool = get_root_pool( stake_delegations );
288 :
289 0 : fd_accdb_ro_pipe_t ro_pipe[1];
290 0 : fd_accdb_ro_pipe_init( ro_pipe, accdb, xid );
291 0 : ulong const job_cnt = fd_stake_delegations_cnt( stake_delegations );
292 0 : for( ulong i=0UL; i<job_cnt; i++ ) {
293 :
294 : /* stream out read requests */
295 0 : fd_accdb_ro_pipe_enqueue( ro_pipe, &pool[ i ].stake_account );
296 0 : if( FD_UNLIKELY( i+1UL==job_cnt ) ) {
297 0 : fd_accdb_ro_pipe_flush( ro_pipe );
298 0 : }
299 :
300 : /* handle a batch of completions */
301 0 : fd_accdb_ro_t * ro;
302 0 : while( (ro = fd_accdb_ro_pipe_poll( ro_pipe )) ) {
303 0 : fd_pubkey_t const * address = fd_accdb_ref_address( ro );
304 0 : fd_stake_delegation_t * delegation = root_map_ele_query( map, address, NULL, pool );
305 0 : if( FD_UNLIKELY( !delegation ) ) continue;
306 :
307 0 : fd_stake_state_t const * stake = fd_stakes_get_state( ro->meta );
308 0 : if( FD_UNLIKELY( !stake ) ) goto remove;
309 0 : if( FD_UNLIKELY( stake->stake_type != FD_STAKE_STATE_STAKE ) ) goto remove;
310 :
311 0 : fd_stake_delegations_root_update(
312 0 : stake_delegations,
313 0 : address,
314 0 : &stake->stake.stake.delegation.voter_pubkey,
315 0 : stake->stake.stake.delegation.stake,
316 0 : stake->stake.stake.delegation.activation_epoch,
317 0 : stake->stake.stake.delegation.deactivation_epoch,
318 0 : stake->stake.stake.credits_observed,
319 0 : stake->stake.stake.delegation.warmup_cooldown_rate );
320 :
321 0 : fd_stake_history_entry_t entry = stake_activating_and_deactivating( &stake->stake.stake.delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
322 0 : stake_delegations->effective_stake += entry.effective;
323 0 : stake_delegations->activating_stake += entry.activating;
324 0 : stake_delegations->deactivating_stake += entry.deactivating;
325 0 : continue; /* ok */
326 :
327 0 : remove:
328 0 : root_map_idx_remove( map, address, UINT_MAX, pool );
329 0 : root_pool_ele_release( pool, delegation );
330 0 : }
331 0 : }
332 0 : fd_accdb_ro_pipe_fini( ro_pipe );
333 0 : }
334 :
335 : #endif
336 :
337 : ulong
338 69 : fd_stake_delegations_cnt( fd_stake_delegations_t const * stake_delegations ) {
339 69 : return root_pool_used( get_root_pool( stake_delegations ) );
340 69 : }
341 :
342 : /* Fork-aware delta operations */
343 :
344 : ushort
345 699 : fd_stake_delegations_new_fork( fd_stake_delegations_t * stake_delegations ) {
346 699 : fork_pool_ele_t * fork_pool = get_fork_pool( stake_delegations );
347 699 : FD_CRIT( fork_pool_free( fork_pool ), "no free forks in pool. The system has forked too wide." );
348 699 : ushort fork_idx = (ushort)fork_pool_idx_acquire( fork_pool );
349 :
350 699 : return fork_idx;
351 699 : }
352 :
353 : void
354 : fd_stake_delegations_fork_update( fd_stake_delegations_t * stake_delegations,
355 : ushort fork_idx,
356 : fd_pubkey_t const * stake_account,
357 : fd_pubkey_t const * vote_account,
358 : ulong stake,
359 : ulong activation_epoch,
360 : ulong deactivation_epoch,
361 : ulong credits_observed,
362 105 : double warmup_cooldown_rate ) {
363 105 : fd_rwlock_write( &stake_delegations->delta_lock );
364 :
365 105 : fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
366 105 : FD_CRIT( delta_pool_free( delta_pool ), "no free stake delegations in pool" );
367 :
368 105 : fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
369 :
370 105 : fd_stake_delegation_t * stake_delegation = delta_pool_ele_acquire( delta_pool );
371 :
372 105 : fork_dlist_ele_push_tail( dlist, stake_delegation, delta_pool );
373 :
374 105 : stake_delegation->stake_account = *stake_account;
375 105 : stake_delegation->vote_account = *vote_account;
376 105 : stake_delegation->stake = stake;
377 105 : stake_delegation->activation_epoch = (ushort)fd_ulong_min( activation_epoch, USHORT_MAX );
378 105 : stake_delegation->deactivation_epoch = (ushort)fd_ulong_min( deactivation_epoch, USHORT_MAX );
379 105 : stake_delegation->credits_observed = credits_observed;
380 105 : stake_delegation->warmup_cooldown_rate = fd_stake_delegations_warmup_cooldown_rate_enum( warmup_cooldown_rate );
381 105 : stake_delegation->is_tombstone = 0;
382 :
383 105 : fd_rwlock_unwrite( &stake_delegations->delta_lock );
384 105 : }
385 :
386 : void
387 : fd_stake_delegations_fork_remove( fd_stake_delegations_t * stake_delegations,
388 : ushort fork_idx,
389 27 : fd_pubkey_t const * stake_account ) {
390 27 : fd_rwlock_write( &stake_delegations->delta_lock );
391 :
392 27 : fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
393 27 : FD_CRIT( delta_pool_free( delta_pool ), "no free stake delegations in pool" );
394 :
395 27 : fd_stake_delegation_t * stake_delegation = delta_pool_ele_acquire( delta_pool );
396 :
397 27 : fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
398 27 : fork_dlist_ele_push_tail( dlist, stake_delegation, delta_pool );
399 :
400 27 : stake_delegation->stake_account = *stake_account;
401 27 : stake_delegation->is_tombstone = 1;
402 :
403 27 : fd_rwlock_unwrite( &stake_delegations->delta_lock );
404 27 : }
405 :
406 : void
407 : fd_stake_delegations_evict_fork( fd_stake_delegations_t * stake_delegations,
408 201 : ushort fork_idx ) {
409 201 : if( fork_idx==USHORT_MAX ) return;
410 :
411 195 : fd_rwlock_write( &stake_delegations->delta_lock );
412 :
413 195 : fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
414 :
415 195 : fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
416 324 : while( !fork_dlist_is_empty( dlist, delta_pool ) ) {
417 129 : fd_stake_delegation_t * ele = fork_dlist_ele_pop_head( dlist, delta_pool );
418 129 : delta_pool_ele_release( delta_pool, ele );
419 129 : }
420 :
421 195 : fork_pool_idx_release( get_fork_pool( stake_delegations ), fork_idx );
422 :
423 195 : fd_rwlock_unwrite( &stake_delegations->delta_lock );
424 195 : }
425 :
426 : void
427 : fd_stake_delegations_apply_fork_delta( ulong epoch,
428 : fd_stake_history_t const * stake_history,
429 : ulong * warmup_cooldown_rate_epoch,
430 : fd_stake_delegations_t * stake_delegations,
431 72 : ushort fork_idx ) {
432 :
433 72 : fork_dlist_t * dlist = get_fork_dlist( stake_delegations, fork_idx );
434 72 : fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
435 :
436 72 : for( fork_dlist_iter_t iter = fork_dlist_iter_fwd_init( dlist, delta_pool );
437 102 : !fork_dlist_iter_done( iter, dlist, delta_pool );
438 72 : iter = fork_dlist_iter_fwd_next( iter, dlist, delta_pool ) ) {
439 30 : fd_stake_delegation_t * stake_delegation = fork_dlist_iter_ele( iter, dlist, delta_pool );
440 30 : if( FD_LIKELY( !stake_delegation->is_tombstone ) ) {
441 : /* If the entry in the delta is an update:
442 : - If the entry already exists, subtract the old version's stake
443 : - Insert/update the new version
444 : - Add the new version's stake to the totals */
445 27 : fd_stake_delegation_t const * old_delegation = fd_stake_delegation_root_query( stake_delegations, &stake_delegation->stake_account );
446 27 : if( FD_LIKELY( old_delegation ) ) {
447 12 : fd_stake_history_entry_t old_entry = fd_stakes_activating_and_deactivating( old_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
448 12 : stake_delegations->effective_stake -= old_entry.effective;
449 12 : stake_delegations->activating_stake -= old_entry.activating;
450 12 : stake_delegations->deactivating_stake -= old_entry.deactivating;
451 12 : }
452 :
453 27 : fd_stake_delegations_root_update(
454 27 : stake_delegations,
455 27 : &stake_delegation->stake_account,
456 27 : &stake_delegation->vote_account,
457 27 : stake_delegation->stake,
458 27 : stake_delegation->activation_epoch,
459 27 : stake_delegation->deactivation_epoch,
460 27 : stake_delegation->credits_observed,
461 27 : fd_stake_delegations_warmup_cooldown_rate_to_double( stake_delegation->warmup_cooldown_rate ) );
462 :
463 27 : fd_stake_history_entry_t new_entry = fd_stakes_activating_and_deactivating( stake_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
464 27 : stake_delegations->effective_stake += new_entry.effective;
465 27 : stake_delegations->activating_stake += new_entry.activating;
466 27 : stake_delegations->deactivating_stake += new_entry.deactivating;
467 27 : } else {
468 : /* If the stake delegation in the delta is a tombstone, just
469 : remove the stake delegation from the root map and subtract
470 : it's stake from the totals. */
471 3 : fd_stake_delegation_t const * old_delegation = fd_stake_delegation_root_query( stake_delegations, &stake_delegation->stake_account );
472 3 : if( FD_LIKELY( old_delegation ) ) {
473 3 : fd_stake_history_entry_t old_entry = fd_stakes_activating_and_deactivating( old_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
474 3 : stake_delegations->effective_stake -= old_entry.effective;
475 3 : stake_delegations->activating_stake -= old_entry.activating;
476 3 : stake_delegations->deactivating_stake -= old_entry.deactivating;
477 3 : }
478 3 : fd_stake_delegations_remove( stake_delegations, &stake_delegation->stake_account );
479 3 : }
480 30 : }
481 72 : }
482 :
483 : /* Combined base+delta iterator */
484 :
485 : fd_stake_delegation_t const *
486 369 : fd_stake_delegations_iter_ele( fd_stake_delegations_iter_t * iter ) {
487 369 : ulong idx = root_map_iter_idx( iter->iter, iter->root_map, iter->root_pool );
488 369 : fd_stake_delegation_t * stake_delegation = root_pool_ele( iter->root_pool, idx );
489 369 : if( FD_UNLIKELY( stake_delegation->delta_idx!=UINT_MAX ) ) {
490 132 : return (fd_stake_delegation_t *)delta_pool_ele( iter->delta_pool, stake_delegation->delta_idx );
491 132 : }
492 237 : return stake_delegation;
493 369 : }
494 :
495 : ulong
496 27 : fd_stake_delegations_iter_idx( fd_stake_delegations_iter_t * iter ) {
497 27 : return root_map_iter_idx( iter->iter, iter->root_map, iter->root_pool );
498 27 : }
499 :
500 : static void
501 450 : skip_tombstones( fd_stake_delegations_iter_t * iter ) {
502 462 : while( !root_map_iter_done( iter->iter, iter->root_map, iter->root_pool ) ) {
503 381 : fd_stake_delegation_t * root_delegation = root_map_iter_ele( iter->iter, iter->root_map, iter->root_pool );
504 381 : fd_stake_delegation_t const * ele = (root_delegation->delta_idx != UINT_MAX)
505 381 : ? (fd_stake_delegation_t const *)delta_pool_ele( iter->delta_pool, root_delegation->delta_idx )
506 381 : : (fd_stake_delegation_t const *)root_delegation;
507 381 : if( FD_LIKELY( !ele->is_tombstone ) ) return;
508 12 : iter->iter = root_map_iter_next( iter->iter, iter->root_map, iter->root_pool );
509 12 : }
510 450 : }
511 :
512 : fd_stake_delegations_iter_t *
513 : fd_stake_delegations_iter_init( fd_stake_delegations_iter_t * iter,
514 222 : fd_stake_delegations_t const * stake_delegations ) {
515 222 : if( FD_UNLIKELY( !stake_delegations ) ) {
516 0 : FD_LOG_CRIT(( "NULL stake_delegations" ));
517 0 : }
518 :
519 222 : iter->root_map = get_root_map( stake_delegations );
520 222 : iter->root_pool = get_root_pool( stake_delegations );
521 222 : iter->iter = root_map_iter_init( iter->root_map, iter->root_pool );
522 222 : iter->delta_pool = get_delta_pool( stake_delegations );
523 :
524 222 : skip_tombstones( iter );
525 :
526 222 : return iter;
527 222 : }
528 :
529 : void
530 228 : fd_stake_delegations_iter_next( fd_stake_delegations_iter_t * iter ) {
531 228 : iter->iter = root_map_iter_next( iter->iter, iter->root_map, iter->root_pool );
532 228 : skip_tombstones( iter );
533 228 : }
534 :
535 : int
536 450 : fd_stake_delegations_iter_done( fd_stake_delegations_iter_t * iter ) {
537 450 : return root_map_iter_done( iter->iter, iter->root_map, iter->root_pool );
538 450 : }
539 :
540 : void
541 : fd_stake_delegations_mark_delta( fd_stake_delegations_t * stake_delegations,
542 : ulong epoch,
543 : fd_stake_history_t const * stake_history,
544 : ulong * warmup_cooldown_rate_epoch,
545 144 : ushort fork_idx ) {
546 :
547 144 : root_map_t * root_map = get_root_map( stake_delegations );
548 144 : fd_stake_delegation_t * root_pool = get_root_pool( stake_delegations );
549 144 : fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
550 144 : fork_dlist_t * fork_dlist = get_fork_dlist( stake_delegations, fork_idx );
551 :
552 144 : for( fork_dlist_iter_t iter = fork_dlist_iter_fwd_init( fork_dlist, delta_pool );
553 309 : !fork_dlist_iter_done( iter, fork_dlist, delta_pool );
554 165 : iter = fork_dlist_iter_fwd_next( iter, fork_dlist, delta_pool ) ) {
555 165 : fd_stake_delegation_t * delta_delegation = fork_dlist_iter_ele( iter, fork_dlist, delta_pool );
556 :
557 165 : fd_stake_delegation_t * base_delegation = root_map_ele_query( root_map, &delta_delegation->stake_account, NULL, root_pool);
558 165 : if( FD_UNLIKELY( !base_delegation ) ) {
559 66 : base_delegation = root_pool_ele_acquire( root_pool );
560 66 : base_delegation->stake_account = delta_delegation->stake_account;
561 66 : base_delegation->dne_in_root = 1;
562 66 : base_delegation->delta_idx = (uint)delta_pool_idx( delta_pool, delta_delegation );
563 66 : root_map_ele_insert( root_map, base_delegation, root_pool );
564 99 : } else {
565 : /* Only subtract the old version's stake if it's not a tombstone.*/
566 99 : fd_stake_delegation_t * old_delegation = base_delegation->delta_idx==UINT_MAX ? base_delegation : delta_pool_ele( delta_pool, base_delegation->delta_idx );
567 99 : if( FD_LIKELY( base_delegation->delta_idx==UINT_MAX || !old_delegation->is_tombstone ) ) {
568 90 : fd_stake_history_entry_t old_entry = fd_stakes_activating_and_deactivating( old_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
569 90 : stake_delegations->effective_stake -= old_entry.effective;
570 90 : stake_delegations->activating_stake -= old_entry.activating;
571 90 : stake_delegations->deactivating_stake -= old_entry.deactivating;
572 90 : }
573 : /* Update the base delegation to point to the new version. */
574 99 : base_delegation->delta_idx = (uint)delta_pool_idx( delta_pool, delta_delegation );
575 99 : }
576 :
577 : /* Add the new version's stake to the totals (as long as it's not a
578 : tombstone).*/
579 165 : if( FD_LIKELY( !delta_delegation->is_tombstone ) ) {
580 141 : fd_stake_history_entry_t new_entry = fd_stakes_activating_and_deactivating( delta_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
581 141 : stake_delegations->effective_stake += new_entry.effective;
582 141 : stake_delegations->activating_stake += new_entry.activating;
583 141 : stake_delegations->deactivating_stake += new_entry.deactivating;
584 141 : }
585 165 : }
586 144 : }
587 :
588 : void
589 : fd_stake_delegations_unmark_delta( fd_stake_delegations_t * stake_delegations,
590 : ulong epoch,
591 : fd_stake_history_t const * stake_history,
592 : ulong * warmup_cooldown_rate_epoch,
593 144 : ushort fork_idx ) {
594 :
595 144 : root_map_t * root_map = get_root_map( stake_delegations );
596 144 : fd_stake_delegation_t * root_pool = get_root_pool( stake_delegations );
597 144 : fork_dlist_t * fork_dlist = get_fork_dlist( stake_delegations, fork_idx );
598 144 : fd_stake_delegation_t * delta_pool = get_delta_pool( stake_delegations );
599 :
600 144 : for( fork_dlist_iter_t iter = fork_dlist_iter_fwd_init( fork_dlist, delta_pool );
601 309 : !fork_dlist_iter_done( iter, fork_dlist, delta_pool );
602 165 : iter = fork_dlist_iter_fwd_next( iter, fork_dlist, delta_pool ) ) {
603 165 : fd_stake_delegation_t * delta_delegation = fork_dlist_iter_ele( iter, fork_dlist, delta_pool );
604 :
605 165 : fd_stake_delegation_t * base_delegation = root_map_ele_query( root_map, &delta_delegation->stake_account, NULL, root_pool );
606 165 : if( FD_UNLIKELY( !base_delegation ) ) {
607 0 : continue;
608 0 : }
609 :
610 165 : uint delta_idx = (uint)delta_pool_idx( delta_pool, delta_delegation );
611 165 : if( FD_UNLIKELY( base_delegation->delta_idx!=delta_idx ) ) continue;
612 :
613 117 : if( FD_UNLIKELY( base_delegation->dne_in_root )) {
614 66 : if( FD_LIKELY( !delta_delegation->is_tombstone ) ) {
615 63 : fd_stake_history_entry_t entry = fd_stakes_activating_and_deactivating( delta_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
616 63 : stake_delegations->effective_stake -= entry.effective;
617 63 : stake_delegations->activating_stake -= entry.activating;
618 63 : stake_delegations->deactivating_stake -= entry.deactivating;
619 63 : }
620 :
621 66 : base_delegation->dne_in_root = 0;
622 66 : base_delegation->delta_idx = UINT_MAX;
623 66 : root_map_ele_remove( root_map, &delta_delegation->stake_account, NULL, root_pool );
624 66 : root_pool_ele_release( root_pool, base_delegation );
625 :
626 66 : } else {
627 51 : if( FD_LIKELY( !delta_delegation->is_tombstone ) ) {
628 39 : fd_stake_history_entry_t entry = fd_stakes_activating_and_deactivating( delta_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
629 39 : stake_delegations->effective_stake -= entry.effective;
630 39 : stake_delegations->activating_stake -= entry.activating;
631 39 : stake_delegations->deactivating_stake -= entry.deactivating;
632 39 : }
633 :
634 51 : base_delegation->delta_idx = UINT_MAX;
635 :
636 51 : fd_stake_history_entry_t entry = fd_stakes_activating_and_deactivating( base_delegation, epoch, stake_history, warmup_cooldown_rate_epoch );
637 51 : stake_delegations->effective_stake += entry.effective;
638 51 : stake_delegations->activating_stake += entry.activating;
639 51 : stake_delegations->deactivating_stake += entry.deactivating;
640 51 : }
641 117 : }
642 144 : }
|