Line data Source code
1 : #include "fd_stake_delegations.h"
2 : #include "../../funk/fd_funk_base.h"
3 : #include "../runtime/fd_txn_account.h"
4 : #include "../runtime/fd_acc_mgr.h"
5 : #include "../runtime/program/fd_stake_program.h"
6 :
7 : #define POOL_NAME fd_stake_delegation_pool
8 534 : #define POOL_T fd_stake_delegation_t
9 18298812 : #define POOL_NEXT next_
10 : #include "../../util/tmpl/fd_pool.c"
11 :
12 : #define MAP_NAME fd_stake_delegation_map
13 : #define MAP_KEY_T fd_pubkey_t
14 : #define MAP_ELE_T fd_stake_delegation_t
15 102 : #define MAP_KEY stake_account
16 144 : #define MAP_KEY_EQ(k0,k1) (fd_pubkey_eq( k0, k1 ))
17 354 : #define MAP_KEY_HASH(key,seed) (fd_funk_rec_key_hash1( key->uc, seed ))
18 204 : #define MAP_NEXT next_
19 : #include "../../util/tmpl/fd_map_chain.c"
20 :
21 : static inline fd_stake_delegation_t *
22 372 : fd_stake_delegations_get_pool( fd_stake_delegations_t const * stake_delegations ) {
23 372 : return fd_stake_delegation_pool_join( (uchar *)stake_delegations + stake_delegations->pool_offset_ );
24 372 : }
25 :
26 : static inline fd_stake_delegation_map_t *
27 297 : fd_stake_delegations_get_map( fd_stake_delegations_t const * stake_delegations ) {
28 297 : return fd_stake_delegation_map_join( (uchar *)stake_delegations + stake_delegations->map_offset_ );
29 297 : }
30 :
31 : ulong
32 1359 : fd_stake_delegations_align( void ) {
33 : /* The align of the struct should be the max of the align of the data
34 : structures that it contains. In this case, this is the map, the
35 : pool, and the struct itself. */
36 1359 : return fd_ulong_max( fd_ulong_max( fd_stake_delegation_map_align(),
37 1359 : fd_stake_delegation_pool_align() ), alignof(fd_stake_delegations_t) );
38 1359 : }
39 :
40 : ulong
41 171 : fd_stake_delegations_footprint( ulong max_stake_accounts ) {
42 :
43 171 : ulong map_chain_cnt = fd_stake_delegation_map_chain_cnt_est( max_stake_accounts );
44 :
45 171 : ulong l = FD_LAYOUT_INIT;
46 171 : l = FD_LAYOUT_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
47 171 : l = FD_LAYOUT_APPEND( l, fd_stake_delegation_pool_align(), fd_stake_delegation_pool_footprint( max_stake_accounts ) );
48 171 : l = FD_LAYOUT_APPEND( l, fd_stake_delegation_map_align(), fd_stake_delegation_map_footprint( map_chain_cnt ) );
49 171 : return FD_LAYOUT_FINI( l, fd_stake_delegations_align() );
50 171 : }
51 :
52 : void *
53 : fd_stake_delegations_new( void * mem,
54 : ulong max_stake_accounts,
55 33 : int leave_tombstones ) {
56 33 : if( FD_UNLIKELY( !mem ) ) {
57 3 : FD_LOG_WARNING(( "NULL mem" ));
58 3 : return NULL;
59 3 : }
60 :
61 30 : if( FD_UNLIKELY( !max_stake_accounts ) ) {
62 3 : FD_LOG_WARNING(( "max_stake_accounts is 0" ));
63 3 : return NULL;
64 3 : }
65 :
66 27 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_stake_delegations_align() ) ) ) {
67 0 : FD_LOG_WARNING(( "misaligned mem" ));
68 0 : return NULL;
69 0 : }
70 :
71 27 : ulong map_chain_cnt = fd_stake_delegation_map_chain_cnt_est( max_stake_accounts );
72 :
73 27 : FD_SCRATCH_ALLOC_INIT( l, mem );
74 27 : fd_stake_delegations_t * stake_delegations = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
75 27 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegation_pool_align(), fd_stake_delegation_pool_footprint( max_stake_accounts ) );
76 27 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegation_map_align(), fd_stake_delegation_map_footprint( map_chain_cnt ) );
77 :
78 27 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_stake_delegations_align() )!=(ulong)mem+fd_stake_delegations_footprint( max_stake_accounts ) ) ) {
79 0 : FD_LOG_WARNING(( "fd_stake_delegations_new: bad layout" ));
80 0 : return NULL;
81 0 : }
82 :
83 27 : if( FD_UNLIKELY( !fd_stake_delegation_pool_new( pool_mem, max_stake_accounts ) ) ) {
84 0 : FD_LOG_WARNING(( "Failed to create stake delegations pool" ));
85 0 : return NULL;
86 0 : }
87 :
88 : /* TODO: The seed shouldn't be hardcoded. */
89 27 : if( FD_UNLIKELY( !fd_stake_delegation_map_new( map_mem, map_chain_cnt, 999UL ) ) ) {
90 0 : FD_LOG_WARNING(( "Failed to create stake delegations map" ));
91 0 : return NULL;
92 0 : }
93 :
94 27 : stake_delegations->pool_offset_ = (ulong)pool_mem - (ulong)mem;
95 27 : stake_delegations->map_offset_ = (ulong)map_mem - (ulong)mem;
96 27 : stake_delegations->max_stake_accounts_ = max_stake_accounts;
97 27 : stake_delegations->leave_tombstones_ = leave_tombstones;
98 :
99 27 : FD_COMPILER_MFENCE();
100 27 : FD_VOLATILE( stake_delegations->magic ) = FD_STAKE_DELEGATIONS_MAGIC;
101 27 : FD_COMPILER_MFENCE();
102 :
103 27 : return mem;
104 27 : }
105 :
106 : fd_stake_delegations_t *
107 144 : fd_stake_delegations_join( void * mem ) {
108 144 : if( FD_UNLIKELY( !mem ) ) {
109 3 : FD_LOG_WARNING(( "NULL mem" ));
110 3 : return NULL;
111 3 : }
112 :
113 141 : 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 141 : fd_stake_delegations_t * stake_delegations = (fd_stake_delegations_t *)mem;
119 :
120 141 : if( FD_UNLIKELY( stake_delegations->magic != FD_STAKE_DELEGATIONS_MAGIC ) ) {
121 6 : FD_LOG_WARNING(( "Invalid stake delegations magic" ));
122 6 : return NULL;
123 6 : }
124 :
125 135 : ulong map_chain_cnt = fd_stake_delegation_map_chain_cnt_est( stake_delegations->max_stake_accounts_ );
126 :
127 135 : FD_SCRATCH_ALLOC_INIT( l, stake_delegations );
128 135 : stake_delegations = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(), sizeof(fd_stake_delegations_t) );
129 135 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegation_pool_align(), fd_stake_delegation_pool_footprint( stake_delegations->max_stake_accounts_ ) );
130 135 : void * map_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegation_map_align(), fd_stake_delegation_map_footprint( map_chain_cnt ) );
131 :
132 135 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_stake_delegations_align() )!=(ulong)mem+fd_stake_delegations_footprint( stake_delegations->max_stake_accounts_ ) ) ) {
133 0 : FD_LOG_WARNING(( "fd_stake_delegations_join: bad layout" ));
134 0 : return NULL;
135 0 : }
136 :
137 135 : if( FD_UNLIKELY( !fd_stake_delegation_pool_join( pool_mem ) ) ) {
138 0 : FD_LOG_WARNING(( "Failed to join stake delegations pool" ));
139 0 : return NULL;
140 0 : }
141 :
142 135 : if( FD_UNLIKELY( !fd_stake_delegation_map_join( map_mem ) ) ) {
143 0 : FD_LOG_WARNING(( "Failed to join stake delegations map" ));
144 0 : return NULL;
145 0 : }
146 :
147 135 : return stake_delegations;
148 135 : }
149 :
150 : void *
151 12 : fd_stake_delegations_leave( fd_stake_delegations_t * self ) {
152 12 : if( FD_UNLIKELY( !self ) ) {
153 3 : FD_LOG_WARNING(( "NULL self" ));
154 3 : return NULL;
155 3 : }
156 :
157 9 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)self, fd_stake_delegations_align() ) ) ) {
158 0 : FD_LOG_WARNING(( "misaligned self" ));
159 0 : return NULL;
160 0 : }
161 :
162 9 : fd_stake_delegations_t * stake_delegations = (fd_stake_delegations_t *)self;
163 :
164 9 : if( FD_UNLIKELY( stake_delegations->magic!=FD_STAKE_DELEGATIONS_MAGIC ) ) {
165 0 : FD_LOG_WARNING(( "Invalid stake delegations magic" ));
166 0 : return NULL;
167 0 : }
168 :
169 9 : return (void *)self;
170 9 : }
171 :
172 : void *
173 6 : fd_stake_delegations_delete( void * mem ) {
174 6 : if( FD_UNLIKELY( !mem ) ) {
175 3 : FD_LOG_WARNING(( "NULL mem" ));
176 3 : return NULL;
177 3 : }
178 :
179 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_stake_delegations_align() ) ) ) {
180 0 : FD_LOG_WARNING(( "misaligned mem" ));
181 0 : return NULL;
182 0 : }
183 :
184 3 : fd_stake_delegations_t * stake_delegations = (fd_stake_delegations_t *)mem;
185 :
186 3 : if( FD_UNLIKELY( stake_delegations->magic!=FD_STAKE_DELEGATIONS_MAGIC ) ) {
187 0 : FD_LOG_WARNING(( "Invalid stake delegations magic" ));
188 0 : return NULL;
189 0 : }
190 :
191 3 : stake_delegations->magic = 0UL;
192 :
193 3 : return mem;
194 3 : }
195 :
196 : void
197 : fd_stake_delegations_update( fd_stake_delegations_t * stake_delegations,
198 : fd_pubkey_t const * stake_account,
199 : fd_pubkey_t const * vote_account,
200 : ulong stake,
201 : ulong activation_epoch,
202 : ulong deactivation_epoch,
203 : ulong credits_observed,
204 117 : double warmup_cooldown_rate ) {
205 117 : fd_stake_delegation_t * stake_delegation_pool = fd_stake_delegations_get_pool( stake_delegations );
206 117 : if( FD_UNLIKELY( !stake_delegation_pool ) ) {
207 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation pool" ));
208 0 : }
209 117 : fd_stake_delegation_map_t * stake_delegation_map = fd_stake_delegations_get_map( stake_delegations );
210 117 : if( FD_UNLIKELY( !stake_delegation_map ) ) {
211 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation map" ));
212 0 : }
213 :
214 : /* First, handle the case where the stake delegation already exists
215 : and we just need to update the entry. The reason we do a const idx
216 : query is to allow fd_stake_delegations_update to be called while
217 : iterating over the map. It is unsafe to call
218 : fd_stake_delegation_map_ele_query() during iteration, but we only
219 : need to change fields which are not used for pool/map management. */
220 :
221 117 : ulong idx = fd_stake_delegation_map_idx_query_const(
222 117 : stake_delegation_map,
223 117 : stake_account,
224 117 : ULONG_MAX,
225 117 : stake_delegation_pool );
226 :
227 117 : if( idx!=ULONG_MAX ) {
228 :
229 21 : fd_stake_delegation_t * stake_delegation = fd_stake_delegation_pool_ele( stake_delegation_pool, idx );
230 21 : if( FD_UNLIKELY( !stake_delegation ) ) {
231 0 : FD_LOG_CRIT(( "unable to retrieve stake delegation" ));
232 0 : }
233 :
234 21 : stake_delegation->vote_account = *vote_account;
235 21 : stake_delegation->stake = stake;
236 21 : stake_delegation->activation_epoch = activation_epoch;
237 21 : stake_delegation->deactivation_epoch = deactivation_epoch;
238 21 : stake_delegation->credits_observed = credits_observed;
239 21 : stake_delegation->warmup_cooldown_rate = warmup_cooldown_rate;
240 21 : stake_delegation->is_tombstone = 0;
241 21 : return;
242 21 : }
243 :
244 : /* Otherwise, try to acquire a new node and populate it. */
245 96 : if( FD_UNLIKELY( !fd_stake_delegation_pool_free( stake_delegation_pool ) ) ) {
246 0 : FD_LOG_CRIT(( "no free stake delegations in pool" ));
247 0 : }
248 :
249 96 : fd_stake_delegation_t * stake_delegation = fd_stake_delegation_pool_ele_acquire( stake_delegation_pool );
250 :
251 96 : stake_delegation->stake_account = *stake_account;
252 96 : stake_delegation->vote_account = *vote_account;
253 96 : stake_delegation->stake = stake;
254 96 : stake_delegation->activation_epoch = activation_epoch;
255 96 : stake_delegation->deactivation_epoch = deactivation_epoch;
256 96 : stake_delegation->credits_observed = credits_observed;
257 96 : stake_delegation->warmup_cooldown_rate = warmup_cooldown_rate;
258 96 : stake_delegation->is_tombstone = 0;
259 :
260 96 : if( FD_UNLIKELY( !fd_stake_delegation_map_ele_insert(
261 96 : stake_delegation_map,
262 96 : stake_delegation,
263 96 : stake_delegation_pool ) ) ) {
264 0 : FD_LOG_CRIT(( "unable to insert stake delegation into map" ));
265 0 : }
266 :
267 96 : }
268 :
269 : void
270 : fd_stake_delegations_remove( fd_stake_delegations_t * stake_delegations,
271 24 : fd_pubkey_t const * stake_account ) {
272 24 : fd_stake_delegation_t * stake_delegation_pool = fd_stake_delegations_get_pool( stake_delegations );
273 24 : if( FD_UNLIKELY( !stake_delegation_pool ) ) {
274 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation pool" ));
275 0 : }
276 24 : fd_stake_delegation_map_t * stake_delegation_map = fd_stake_delegations_get_map( stake_delegations );
277 24 : if( FD_UNLIKELY( !stake_delegation_map ) ) {
278 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation map" ));
279 0 : }
280 :
281 24 : ulong delegation_idx = fd_stake_delegation_map_idx_query(
282 24 : stake_delegation_map,
283 24 : stake_account,
284 24 : ULONG_MAX,
285 24 : stake_delegation_pool );
286 :
287 24 : if( stake_delegations->leave_tombstones_==1 ) {
288 : /* If we are configured to leave tombstones, we need to either
289 : update the entry's is_tombstone flag or insert a new entry. */
290 :
291 9 : fd_stake_delegation_t * stake_delegation = NULL;
292 9 : if( delegation_idx!=ULONG_MAX ) {
293 : /* The delegation was found, update the is_tombstone flag. */
294 3 : stake_delegation = fd_stake_delegation_pool_ele( stake_delegation_pool, delegation_idx );
295 6 : } else {
296 : /* Otherwise, acquire an element from the pool and add it into the
297 : map. */
298 6 : stake_delegation = fd_stake_delegation_pool_ele_acquire( stake_delegation_pool );
299 6 : stake_delegation->stake_account = *stake_account;
300 6 : fd_stake_delegation_map_ele_insert( stake_delegation_map, stake_delegation, stake_delegation_pool );
301 6 : }
302 9 : stake_delegation->is_tombstone = 1;
303 :
304 15 : } else {
305 : /* If we are not configured to leave tombstones, we need to remove
306 : the entry from the map and release it from the pool. */
307 15 : if( FD_UNLIKELY( delegation_idx == ULONG_MAX ) ) {
308 : /* The delegation was not found, nothing to do. */
309 0 : return;
310 0 : }
311 :
312 : /* To be safe, we should set the next_ pointer to the null idx. */
313 :
314 15 : fd_stake_delegation_t * stake_delegation = fd_stake_delegation_pool_ele( stake_delegation_pool, delegation_idx );
315 15 : if( FD_UNLIKELY( !stake_delegation ) ) {
316 0 : FD_LOG_CRIT(( "unable to retrieve stake delegation" ));
317 0 : }
318 :
319 15 : ulong idx = fd_stake_delegation_map_idx_remove( stake_delegation_map, stake_account, ULONG_MAX, stake_delegation_pool );
320 15 : if( FD_UNLIKELY( idx==ULONG_MAX ) ) {
321 0 : FD_LOG_CRIT(( "unable to remove stake delegation" ));
322 0 : }
323 :
324 15 : stake_delegation->next_ = fd_stake_delegation_pool_idx_null( stake_delegation_pool );
325 :
326 15 : fd_stake_delegation_pool_idx_release( stake_delegation_pool, delegation_idx );
327 15 : }
328 24 : }
329 :
330 : void
331 : fd_stake_delegations_refresh( fd_stake_delegations_t * stake_delegations,
332 : fd_funk_t * funk,
333 0 : fd_funk_txn_xid_t const * xid ) {
334 :
335 0 : fd_stake_delegation_map_t * stake_delegation_map = fd_stake_delegations_get_map( stake_delegations );
336 0 : if( FD_UNLIKELY( !stake_delegation_map ) ) {
337 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation map" ));
338 0 : }
339 :
340 0 : fd_stake_delegation_t * stake_delegation_pool = fd_stake_delegations_get_pool( stake_delegations );
341 0 : if( FD_UNLIKELY( !stake_delegation_pool ) ) {
342 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation pool" ));
343 0 : }
344 :
345 0 : for( ulong i=0UL; i<stake_delegations->max_stake_accounts_; i++ ) {
346 :
347 0 : fd_stake_delegation_t * stake_delegation = fd_stake_delegation_pool_ele( fd_stake_delegations_get_pool( stake_delegations ), i );
348 :
349 0 : if( !fd_stake_delegation_map_ele_query_const(
350 0 : fd_stake_delegations_get_map( stake_delegations ),
351 0 : &stake_delegation->stake_account,
352 0 : NULL,
353 0 : fd_stake_delegations_get_pool( stake_delegations ) ) ) {
354 : /* This means that the stake delegation is not in the map, so we
355 : can skip it. */
356 0 : continue;
357 0 : }
358 :
359 0 : int err = 0;
360 0 : fd_account_meta_t const * meta = fd_funk_get_acc_meta_readonly( funk, xid, &stake_delegation->stake_account, NULL, &err, NULL );
361 0 : if( FD_UNLIKELY( err || meta->lamports==0UL ) ) {
362 0 : fd_stake_delegation_map_idx_remove( stake_delegation_map, &stake_delegation->stake_account, ULONG_MAX, stake_delegation_pool );
363 0 : fd_stake_delegation_pool_idx_release( stake_delegation_pool, i );
364 0 : continue;
365 0 : }
366 :
367 0 : fd_stake_state_v2_t stake_state;
368 0 : err = fd_stake_get_state( meta, &stake_state );
369 0 : if( FD_UNLIKELY( err ) ) {
370 0 : fd_stake_delegation_map_idx_remove( stake_delegation_map, &stake_delegation->stake_account, ULONG_MAX, stake_delegation_pool );
371 0 : fd_stake_delegation_pool_idx_release( stake_delegation_pool, i );
372 0 : }
373 :
374 0 : if( FD_UNLIKELY( !fd_stake_state_v2_is_stake( &stake_state ) ) ) {
375 0 : fd_stake_delegation_map_idx_remove( stake_delegation_map, &stake_delegation->stake_account, ULONG_MAX, stake_delegation_pool );
376 0 : fd_stake_delegation_pool_idx_release( stake_delegation_pool, i );
377 0 : }
378 :
379 0 : fd_stake_delegations_update(
380 0 : stake_delegations,
381 0 : &stake_delegation->stake_account,
382 0 : &stake_state.inner.stake.stake.delegation.voter_pubkey,
383 0 : stake_state.inner.stake.stake.delegation.stake,
384 0 : stake_state.inner.stake.stake.delegation.activation_epoch,
385 0 : stake_state.inner.stake.stake.delegation.deactivation_epoch,
386 0 : stake_state.inner.stake.stake.credits_observed,
387 0 : stake_state.inner.stake.stake.delegation.warmup_cooldown_rate );
388 0 : }
389 0 : }
390 :
391 : fd_stake_delegation_t const *
392 : fd_stake_delegations_query( fd_stake_delegations_t const * stake_delegations,
393 96 : fd_pubkey_t const * stake_account ) {
394 :
395 96 : if( FD_UNLIKELY( !stake_delegations ) ) {
396 0 : FD_LOG_CRIT(( "NULL stake_delegations" ));
397 0 : return NULL;
398 0 : }
399 :
400 96 : if( FD_UNLIKELY( !stake_account ) ) {
401 0 : FD_LOG_CRIT(( "NULL stake_account" ));
402 0 : return NULL;
403 0 : }
404 :
405 96 : fd_stake_delegation_t const * stake_delegation_pool = fd_stake_delegations_get_pool( stake_delegations );
406 96 : if( FD_UNLIKELY( !stake_delegation_pool ) ) {
407 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation pool" ));
408 0 : }
409 :
410 96 : fd_stake_delegation_map_t const * stake_delegation_map = fd_stake_delegations_get_map( stake_delegations );
411 96 : if( FD_UNLIKELY( !stake_delegation_map ) ) {
412 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation map" ));
413 0 : }
414 :
415 96 : return fd_stake_delegation_map_ele_query_const(
416 96 : stake_delegation_map,
417 96 : stake_account,
418 96 : NULL,
419 96 : stake_delegation_pool );
420 96 : }
421 :
422 : ulong
423 75 : fd_stake_delegations_cnt( fd_stake_delegations_t const * stake_delegations ) {
424 75 : if( FD_UNLIKELY( !stake_delegations ) ) {
425 0 : FD_LOG_CRIT(( "NULL stake_delegations" ));
426 0 : }
427 :
428 75 : fd_stake_delegation_t const * stake_delegation_pool = fd_stake_delegations_get_pool( stake_delegations );
429 75 : if( FD_UNLIKELY( !stake_delegation_pool ) ) {
430 0 : FD_LOG_CRIT(( "unable to retrieve join to stake delegation map" ));
431 0 : }
432 :
433 75 : return fd_stake_delegation_pool_used( stake_delegation_pool );
434 75 : }
435 :
436 : fd_stake_delegation_t *
437 87 : fd_stake_delegations_iter_ele( fd_stake_delegations_iter_t * iter ) {
438 87 : ulong idx = fd_stake_delegation_map_iter_idx( iter->iter, iter->map, iter->pool );
439 87 : return fd_stake_delegation_pool_ele( iter->pool, idx );
440 87 : }
441 :
442 : fd_stake_delegations_iter_t *
443 : fd_stake_delegations_iter_init( fd_stake_delegations_iter_t * iter,
444 60 : fd_stake_delegations_t const * stake_delegations ) {
445 60 : if( FD_UNLIKELY( !stake_delegations ) ) {
446 0 : FD_LOG_CRIT(( "NULL stake_delegations" ));
447 0 : }
448 :
449 60 : iter->map = fd_stake_delegations_get_map( stake_delegations );
450 60 : iter->pool = fd_stake_delegations_get_pool( stake_delegations );
451 60 : iter->iter = fd_stake_delegation_map_iter_init( iter->map, iter->pool );
452 :
453 60 : return iter;
454 60 : }
455 :
456 : void
457 87 : fd_stake_delegations_iter_next( fd_stake_delegations_iter_t * iter ) {
458 87 : iter->iter = fd_stake_delegation_map_iter_next( iter->iter, iter->map, iter->pool );
459 87 : }
460 :
461 : int
462 147 : fd_stake_delegations_iter_done( fd_stake_delegations_iter_t * iter ) {
463 147 : return fd_stake_delegation_map_iter_done( iter->iter, iter->map, iter->pool );
464 147 : }
|