Line data Source code
1 : #include "fd_bank.h"
2 : #include "fd_runtime_const.h"
3 : #include "../rewards/fd_stake_rewards.h"
4 : #include "sysvar/fd_sysvar_cache.h"
5 :
6 : fd_lthash_value_t const *
7 78 : fd_bank_lthash_locking_query( fd_bank_t * bank ) {
8 78 : fd_rwlock_read( &bank->lthash_lock );
9 78 : return &bank->f.lthash;
10 78 : }
11 :
12 : void
13 78 : fd_bank_lthash_end_locking_query( fd_bank_t * bank ) {
14 78 : fd_rwlock_unread( &bank->lthash_lock );
15 78 : }
16 :
17 : fd_lthash_value_t *
18 15516 : fd_bank_lthash_locking_modify( fd_bank_t * bank ) {
19 15516 : fd_rwlock_write( &bank->lthash_lock );
20 15516 : return &bank->f.lthash;
21 15516 : }
22 :
23 : void
24 15516 : fd_bank_lthash_end_locking_modify( fd_bank_t * bank ) {
25 15516 : fd_rwlock_unwrite( &bank->lthash_lock );
26 15516 : }
27 :
28 : ulong
29 10074 : fd_banks_align( void ) {
30 10074 : return FD_BANKS_ALIGN;
31 10074 : }
32 :
33 : static fd_bank_t *
34 120285 : fd_banks_get_bank_pool( fd_banks_t * banks_data ) {
35 120285 : return fd_type_pun( (uchar *)banks_data + banks_data->pool_offset );
36 120285 : }
37 :
38 : static fd_bank_idx_seq_t *
39 3522 : fd_banks_get_dead_banks_deque( fd_banks_t * banks_data ) {
40 3522 : return fd_type_pun( (uchar *)banks_data + banks_data->dead_banks_deque_offset );
41 3522 : }
42 :
43 : static fd_epoch_leaders_t *
44 4170 : fd_banks_get_epoch_leaders( fd_banks_t * banks_data ) {
45 4170 : return fd_type_pun( (uchar *)banks_data + banks_data->epoch_leaders_offset );
46 4170 : }
47 :
48 : static fd_stake_delegations_t *
49 11763 : fd_banks_get_stake_delegations( fd_banks_t * banks_data ) {
50 11763 : return fd_type_pun( (uchar *)banks_data + banks_data->stake_delegations_offset );
51 11763 : }
52 :
53 : static fd_bank_cost_tracker_t *
54 16161 : fd_banks_get_cost_tracker_pool( fd_banks_t * banks_data ) {
55 16161 : return fd_type_pun( (uchar *)banks_data + banks_data->cost_tracker_pool_offset );
56 16161 : }
57 :
58 : static fd_stake_rewards_t *
59 4053 : fd_banks_get_stake_rewards( fd_banks_t * banks_data ) {
60 4053 : return fd_type_pun( (uchar *)banks_data + banks_data->stake_rewards_offset );
61 4053 : }
62 :
63 : static fd_vote_stakes_t *
64 14838 : fd_banks_get_vote_stakes( fd_banks_t * banks_data ) {
65 14838 : return fd_type_pun( (uchar *)banks_data + banks_data->vote_stakes_pool_offset );
66 14838 : }
67 :
68 : static fd_new_votes_t *
69 7467 : fd_banks_get_new_votes( fd_banks_t * banks_data ) {
70 7467 : return fd_type_pun( (uchar *)banks_data + banks_data->new_votes_offset );
71 7467 : }
72 :
73 : static fd_epoch_credits_t *
74 270 : fd_banks_get_epoch_credits( fd_banks_t * banks_data ) {
75 270 : return fd_type_pun( (uchar *)banks_data + banks_data->epoch_credits_offset );
76 270 : }
77 :
78 : static fd_stashed_commission_t *
79 0 : fd_banks_get_snapshot_commission_t_3( fd_banks_t * banks_data ) {
80 0 : return fd_type_pun( (uchar *)banks_data + banks_data->snapshot_commission_t_3_offset );
81 0 : }
82 :
83 : fd_epoch_credits_t *
84 270 : fd_bank_epoch_credits( fd_bank_t * bank ) {
85 270 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
86 270 : return fd_banks_get_epoch_credits( banks_data );
87 270 : }
88 :
89 : ulong *
90 129 : fd_bank_epoch_credits_len( fd_bank_t * bank ) {
91 129 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
92 129 : return &banks_data->epoch_credits_len;
93 129 : }
94 :
95 : fd_stashed_commission_t *
96 0 : fd_bank_snapshot_commission_t_3( fd_bank_t * bank ) {
97 0 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
98 0 : return fd_banks_get_snapshot_commission_t_3( banks_data );
99 0 : }
100 :
101 : ulong *
102 0 : fd_bank_snapshot_commission_t_3_len( fd_bank_t * bank ) {
103 0 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
104 0 : return &banks_data->snapshot_commission_t_3_len;
105 0 : }
106 :
107 : fd_vote_stakes_t *
108 7323 : fd_bank_vote_stakes( fd_bank_t const * bank ) {
109 7323 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
110 7323 : return fd_banks_get_vote_stakes( banks_data );
111 7323 : }
112 :
113 : fd_new_votes_t *
114 150 : fd_bank_new_votes( fd_bank_t const * bank ) {
115 150 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
116 150 : return fd_banks_get_new_votes( banks_data );
117 150 : }
118 :
119 : fd_stake_delegations_t *
120 93 : fd_bank_stake_delegations_modify( fd_bank_t * bank ) {
121 93 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
122 93 : return fd_banks_get_stake_delegations( banks_data );
123 93 : }
124 :
125 : fd_stake_rewards_t const *
126 129 : fd_bank_stake_rewards_query( fd_bank_t * bank ) {
127 129 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
128 129 : return fd_type_pun_const( fd_banks_get_stake_rewards( banks_data ) );
129 129 : }
130 :
131 : fd_stake_rewards_t *
132 486 : fd_bank_stake_rewards_modify( fd_bank_t * bank ) {
133 486 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
134 486 : return fd_banks_get_stake_rewards( banks_data );
135 486 : }
136 :
137 : fd_epoch_leaders_t const *
138 : fd_bank_epoch_leaders_query( fd_bank_t const * bank,
139 18 : ulong epoch ) {
140 18 : FD_TEST( bank->f.epoch==epoch || bank->f.epoch==epoch-1UL );
141 18 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
142 18 : return (fd_epoch_leaders_t const *)fd_type_pun( (uchar *)fd_banks_get_epoch_leaders( banks_data ) + (epoch % 2UL) * banks_data->epoch_leaders_footprint );
143 18 : }
144 :
145 : fd_epoch_leaders_t *
146 : fd_bank_epoch_leaders_modify( fd_bank_t * bank,
147 3561 : ulong epoch ) {
148 3561 : FD_TEST( bank->f.epoch==epoch || bank->f.epoch==epoch-1UL );
149 3561 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
150 3561 : return (fd_epoch_leaders_t *)fd_type_pun( (uchar *)fd_banks_get_epoch_leaders( banks_data ) + (epoch % 2UL) * banks_data->epoch_leaders_footprint );
151 3561 : }
152 :
153 : fd_top_votes_t const *
154 0 : fd_bank_top_votes_t_1_query( fd_bank_t const * bank ) {
155 0 : return fd_type_pun_const( bank->top_votes_t_1_mem );
156 0 : }
157 :
158 : fd_top_votes_t *
159 3546 : fd_bank_top_votes_t_1_modify( fd_bank_t * bank ) {
160 3546 : return fd_type_pun( bank->top_votes_t_1_mem );
161 3546 : }
162 :
163 : fd_top_votes_t const *
164 3657 : fd_bank_top_votes_t_2_query( fd_bank_t const * bank ) {
165 3657 : return fd_type_pun_const( bank->top_votes_t_2_mem );
166 3657 : }
167 :
168 : fd_top_votes_t *
169 3621 : fd_bank_top_votes_t_2_modify( fd_bank_t * bank ) {
170 3621 : return fd_type_pun( bank->top_votes_t_2_mem );
171 3621 : }
172 :
173 : fd_cost_tracker_t *
174 3585 : fd_bank_cost_tracker_modify( fd_bank_t * bank ) {
175 3585 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
176 3585 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks_data );
177 3585 : FD_TEST( bank->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) );
178 3585 : uchar * cost_tracker_mem = fd_bank_cost_tracker_pool_ele( cost_tracker_pool, bank->cost_tracker_pool_idx )->data;
179 3585 : return fd_type_pun( cost_tracker_mem );
180 3585 : }
181 :
182 : fd_cost_tracker_t const *
183 0 : fd_bank_cost_tracker_query( fd_bank_t * bank ) {
184 0 : fd_banks_t * banks_data = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
185 0 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks_data );
186 0 : FD_TEST( bank->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) );
187 0 : uchar * cost_tracker_mem = fd_bank_cost_tracker_pool_ele( cost_tracker_pool, bank->cost_tracker_pool_idx )->data;
188 0 : return fd_type_pun_const( cost_tracker_mem );
189 0 : }
190 :
191 : fd_bank_t *
192 86619 : fd_banks_root( fd_banks_t * banks ) {
193 86619 : return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), banks->root_idx );
194 86619 : }
195 :
196 : fd_bank_t *
197 : fd_banks_bank_query( fd_banks_t * banks,
198 10707 : ulong bank_idx ) {
199 10707 : fd_bank_t * bank = fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank_idx );
200 10707 : if( FD_UNLIKELY( bank->state==FD_BANK_STATE_INACTIVE ) ) return NULL;
201 10650 : return bank;
202 10707 : }
203 :
204 : fd_bank_t *
205 : fd_banks_get_parent( fd_banks_t * banks,
206 0 : fd_bank_t * bank ) {
207 0 : if( FD_UNLIKELY( bank->parent_idx==ULONG_MAX ) ) return NULL;
208 0 : return fd_banks_pool_ele( fd_banks_get_bank_pool( banks ), bank->parent_idx );
209 0 : }
210 :
211 : int
212 0 : fd_banks_is_full( fd_banks_t * banks ) {
213 0 : return fd_banks_pool_free( fd_banks_get_bank_pool( banks ) )==0UL ||
214 0 : fd_bank_cost_tracker_pool_free( fd_banks_get_cost_tracker_pool( banks ) )==0UL;
215 0 : }
216 :
217 : ulong
218 9 : fd_banks_pool_used_cnt( fd_banks_t * banks ) {
219 9 : return fd_banks_pool_used( fd_banks_get_bank_pool( banks ) );
220 9 : }
221 :
222 : ulong
223 6807 : fd_banks_pool_max_cnt( fd_banks_t * banks ) {
224 6807 : return fd_banks_pool_max( fd_banks_get_bank_pool( banks ) );
225 6807 : }
226 :
227 : void
228 : fd_banks_stake_delegations_evict_bank_fork( fd_banks_t * banks,
229 0 : fd_bank_t * bank ) {
230 0 : if( bank->stake_delegations_fork_id!=USHORT_MAX ) {
231 0 : fd_stake_delegations_t * sd = fd_banks_get_stake_delegations( banks );
232 0 : fd_stake_delegations_evict_fork( sd, bank->stake_delegations_fork_id );
233 0 : bank->stake_delegations_fork_id = USHORT_MAX;
234 0 : }
235 0 : }
236 :
237 : ulong
238 : fd_banks_footprint( ulong max_total_banks,
239 : ulong max_fork_width,
240 : ulong max_stake_accounts,
241 1188 : ulong max_vote_accounts ) {
242 :
243 : /* max_fork_width is used in the macro below. */
244 :
245 1188 : ulong epoch_leaders_footprint = FD_EPOCH_LEADERS_FOOTPRINT( max_vote_accounts, FD_RUNTIME_SLOTS_PER_EPOCH );
246 1188 : ulong expected_stake_accounts = fd_ulong_min( max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS );
247 1188 : ulong expected_vote_accounts = fd_ulong_min( max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS );
248 :
249 1188 : ulong l = FD_LAYOUT_INIT;
250 1188 : l = FD_LAYOUT_APPEND( l, fd_banks_align(), sizeof(fd_banks_t) );
251 1188 : l = FD_LAYOUT_APPEND( l, fd_stake_delegations_align(), fd_stake_delegations_footprint( max_stake_accounts, expected_stake_accounts, max_total_banks ) );
252 1188 : l = FD_LAYOUT_APPEND( l, FD_EPOCH_LEADERS_ALIGN, 2UL * epoch_leaders_footprint );
253 1188 : l = FD_LAYOUT_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( max_total_banks ) );
254 1188 : l = FD_LAYOUT_APPEND( l, fd_banks_dead_align(), fd_banks_dead_footprint() );
255 1188 : l = FD_LAYOUT_APPEND( l, fd_bank_cost_tracker_pool_align(), fd_bank_cost_tracker_pool_footprint( max_fork_width ) );
256 1188 : l = FD_LAYOUT_APPEND( l, fd_stake_rewards_align(), fd_stake_rewards_footprint( max_stake_accounts, expected_stake_accounts, max_fork_width ) );
257 1188 : l = FD_LAYOUT_APPEND( l, fd_vote_stakes_align(), fd_vote_stakes_footprint( max_vote_accounts, fd_ulong_min( max_vote_accounts, expected_vote_accounts ), max_fork_width ) );
258 1188 : l = FD_LAYOUT_APPEND( l, fd_new_votes_align(), fd_new_votes_footprint( max_vote_accounts, expected_vote_accounts, max_total_banks ) );
259 1188 : l = FD_LAYOUT_APPEND( l, alignof(fd_epoch_credits_t), sizeof(fd_epoch_credits_t) * max_vote_accounts );
260 1188 : l = FD_LAYOUT_APPEND( l, alignof(fd_stashed_commission_t), sizeof(fd_stashed_commission_t) * max_vote_accounts );
261 1188 : return FD_LAYOUT_FINI( l, fd_banks_align() );
262 1188 : }
263 :
264 : void *
265 : fd_banks_new( void * shmem,
266 : ulong max_total_banks,
267 : ulong max_fork_width,
268 : ulong max_stake_accounts,
269 : ulong max_vote_accounts,
270 : int larger_max_cost_per_block,
271 591 : ulong seed ) {
272 591 : if( FD_UNLIKELY( !shmem ) ) {
273 0 : FD_LOG_WARNING(( "NULL shmem" ));
274 0 : return NULL;
275 0 : }
276 :
277 591 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_banks_align() ) ) ) {
278 0 : FD_LOG_WARNING(( "misaligned shmem" ));
279 0 : return NULL;
280 0 : }
281 :
282 591 : if( FD_UNLIKELY( max_total_banks>FD_BANKS_MAX_BANKS ) ) {
283 0 : FD_LOG_WARNING(( "max_total_banks is too large" ));
284 0 : return NULL;
285 0 : }
286 591 : if( FD_UNLIKELY( max_fork_width>FD_BANKS_MAX_BANKS ) ) {
287 0 : FD_LOG_WARNING(( "max_fork_width is too large" ));
288 0 : return NULL;
289 0 : }
290 :
291 591 : ulong epoch_leaders_footprint = FD_EPOCH_LEADERS_FOOTPRINT( max_vote_accounts, FD_RUNTIME_SLOTS_PER_EPOCH );
292 591 : ulong expected_stake_accounts = fd_ulong_min( max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS );
293 591 : ulong expected_vote_accounts = fd_ulong_min( max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS );
294 :
295 591 : FD_SCRATCH_ALLOC_INIT( l, shmem );
296 591 : fd_banks_t * banks_data = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(), sizeof(fd_banks_t) );
297 591 : void * stake_delegations_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(), fd_stake_delegations_footprint( max_stake_accounts, expected_stake_accounts, max_total_banks ) );
298 591 : void * epoch_leaders_mem = FD_SCRATCH_ALLOC_APPEND( l, FD_EPOCH_LEADERS_ALIGN, 2UL * epoch_leaders_footprint );
299 591 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( max_total_banks ) );
300 591 : void * dead_banks_deque_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_dead_align(), fd_banks_dead_footprint() );
301 591 : void * cost_tracker_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_cost_tracker_pool_align(), fd_bank_cost_tracker_pool_footprint( max_fork_width ) );
302 591 : void * stake_rewards_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_rewards_align(), fd_stake_rewards_footprint( max_stake_accounts, expected_stake_accounts, max_fork_width ) );
303 591 : void * vote_stakes_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(), fd_vote_stakes_footprint( max_vote_accounts, expected_vote_accounts, max_fork_width ) );
304 591 : void * new_votes_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_new_votes_align(), fd_new_votes_footprint( max_vote_accounts, expected_vote_accounts, max_total_banks ) );
305 591 : void * epoch_credits_mem = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_epoch_credits_t), sizeof(fd_epoch_credits_t) * max_vote_accounts );
306 591 : void * snapshot_commission_t_3 = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stashed_commission_t), sizeof(fd_stashed_commission_t) * max_vote_accounts );
307 :
308 591 : if( FD_UNLIKELY( FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() ) != (ulong)banks_data + fd_banks_footprint( max_total_banks, max_fork_width, max_stake_accounts, max_vote_accounts ) ) ) {
309 0 : FD_LOG_WARNING(( "fd_banks_new: bad layout" ));
310 0 : return NULL;
311 0 : }
312 :
313 591 : void * pool = fd_banks_pool_new( pool_mem, max_total_banks );
314 591 : if( FD_UNLIKELY( !pool ) ) {
315 0 : FD_LOG_WARNING(( "Failed to create bank pool" ));
316 0 : return NULL;
317 0 : }
318 :
319 591 : fd_bank_t * bank_pool = fd_banks_pool_join( pool );
320 591 : if( FD_UNLIKELY( !bank_pool ) ) {
321 0 : FD_LOG_WARNING(( "Failed to join bank pool" ));
322 0 : return NULL;
323 0 : }
324 :
325 591 : fd_bank_idx_seq_t * banks_dead_deque = fd_banks_dead_join( fd_banks_dead_new( dead_banks_deque_mem ) );
326 591 : if( FD_UNLIKELY( !banks_dead_deque ) ) {
327 0 : FD_LOG_WARNING(( "Failed to create banks dead deque" ));
328 0 : return NULL;
329 0 : }
330 591 : banks_data->dead_banks_deque_offset = (ulong)banks_dead_deque - (ulong)banks_data;
331 :
332 591 : banks_data->epoch_leaders_offset = (ulong)epoch_leaders_mem - (ulong)banks_data;
333 591 : banks_data->epoch_leaders_footprint = epoch_leaders_footprint;
334 591 : banks_data->pool_offset = (ulong)bank_pool - (ulong)banks_data;
335 591 : banks_data->epoch_credits_offset = (ulong)epoch_credits_mem - (ulong)banks_data;
336 591 : banks_data->snapshot_commission_t_3_offset = (ulong)snapshot_commission_t_3 - (ulong)banks_data;
337 :
338 : /* Create the pools for the non-inlined fields. Also new() and join()
339 : each of the elements in the pool as well as set up the lock for
340 : each of the pools. */
341 :
342 591 : fd_stake_delegations_t * stake_delegations = fd_stake_delegations_join( fd_stake_delegations_new( stake_delegations_mem, seed, max_stake_accounts, expected_stake_accounts, max_total_banks ) );
343 591 : if( FD_UNLIKELY( !stake_delegations ) ) {
344 0 : FD_LOG_WARNING(( "Unable to create stake delegations root" ));
345 0 : return NULL;
346 0 : }
347 591 : banks_data->stake_delegations_offset = (ulong)stake_delegations - (ulong)banks_data;
348 :
349 591 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_bank_cost_tracker_pool_join( fd_bank_cost_tracker_pool_new( cost_tracker_pool_mem, max_fork_width ) );
350 591 : if( FD_UNLIKELY( !cost_tracker_pool ) ) {
351 0 : FD_LOG_WARNING(( "Failed to create cost tracker pool" ));
352 0 : return NULL;
353 0 : }
354 591 : banks_data->cost_tracker_pool_offset = (ulong)cost_tracker_pool - (ulong)banks_data;
355 :
356 1380 : for( ulong i=0UL; i<max_fork_width; i++ ) {
357 789 : fd_bank_cost_tracker_t * cost_tracker = fd_bank_cost_tracker_pool_ele( cost_tracker_pool, i );
358 789 : if( FD_UNLIKELY( !fd_cost_tracker_join( fd_cost_tracker_new( cost_tracker->data, larger_max_cost_per_block, seed ) ) ) ) {
359 0 : FD_LOG_WARNING(( "Failed to create cost tracker" ));
360 0 : return NULL;
361 0 : }
362 789 : }
363 :
364 591 : fd_stake_rewards_t * stake_rewards = fd_stake_rewards_join( fd_stake_rewards_new( stake_rewards_pool_mem, max_stake_accounts, fd_ulong_min( max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS ), max_fork_width, seed ) );
365 591 : if( FD_UNLIKELY( !stake_rewards ) ) {
366 0 : FD_LOG_WARNING(( "Failed to create stake rewards" ));
367 0 : return NULL;
368 0 : }
369 591 : banks_data->stake_rewards_offset = (ulong)stake_rewards - (ulong)banks_data;
370 :
371 :
372 591 : fd_vote_stakes_t * vote_stakes = fd_vote_stakes_join( fd_vote_stakes_new( vote_stakes_mem, max_vote_accounts, fd_ulong_min( max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS ), max_fork_width, seed ) );
373 591 : if( FD_UNLIKELY( !vote_stakes ) ) {
374 0 : FD_LOG_WARNING(( "Failed to create vote stakes" ));
375 0 : return NULL;
376 0 : }
377 591 : banks_data->vote_stakes_pool_offset = (ulong)vote_stakes - (ulong)banks_data;
378 :
379 591 : fd_new_votes_t * new_votes = fd_new_votes_join( fd_new_votes_new( new_votes_mem, seed, max_vote_accounts, expected_vote_accounts, max_total_banks ) );
380 591 : if( FD_UNLIKELY( !new_votes ) ) {
381 0 : FD_LOG_WARNING(( "Failed to create new votes" ));
382 0 : return NULL;
383 0 : }
384 591 : banks_data->new_votes_offset = (ulong)new_votes - (ulong)banks_data;
385 :
386 : /* For each bank, set the offset back to banks_data and initialize
387 : per-bank state. */
388 :
389 591 : fd_bank_cost_tracker_t * cost_tracker_pool_init = fd_banks_get_cost_tracker_pool( banks_data );
390 :
391 2016 : for( ulong i=0UL; i<max_total_banks; i++ ) {
392 :
393 1425 : fd_bank_t * bank = fd_banks_pool_ele( bank_pool, i );
394 :
395 1425 : fd_rwlock_new( &bank->lthash_lock );
396 :
397 1425 : bank->idx = i;
398 1425 : bank->state = FD_BANK_STATE_INACTIVE;
399 1425 : bank->banks_data_offset = (ulong)bank - (ulong)banks_data;
400 :
401 1425 : if( i==0UL ) {
402 591 : FD_TEST( fd_top_votes_join( fd_top_votes_new( bank->top_votes_t_1_mem, FD_RUNTIME_MAX_VOTE_ACCOUNTS_VAT, seed ) ) );
403 591 : FD_TEST( fd_top_votes_join( fd_top_votes_new( bank->top_votes_t_2_mem, FD_RUNTIME_MAX_VOTE_ACCOUNTS_VAT, seed ) ) );
404 591 : }
405 :
406 1425 : bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool_init );
407 1425 : }
408 :
409 591 : banks_data->max_total_banks = max_total_banks;
410 591 : banks_data->max_fork_width = max_fork_width;
411 591 : banks_data->max_stake_accounts = max_stake_accounts;
412 591 : banks_data->max_vote_accounts = max_vote_accounts;
413 591 : banks_data->root_idx = ULONG_MAX;
414 591 : banks_data->bank_seq = 0UL;
415 :
416 591 : FD_COMPILER_MFENCE();
417 591 : FD_VOLATILE( banks_data->magic ) = FD_BANKS_MAGIC;
418 591 : FD_COMPILER_MFENCE();
419 :
420 591 : return shmem;
421 591 : }
422 :
423 : fd_banks_t *
424 591 : fd_banks_join( void * banks_data_mem ) {
425 591 : fd_banks_t * banks_data = (fd_banks_t *)banks_data_mem;
426 :
427 591 : if( FD_UNLIKELY( !banks_data ) ) {
428 0 : FD_LOG_WARNING(( "NULL banks data" ));
429 0 : return NULL;
430 0 : }
431 :
432 591 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)banks_data, fd_banks_align() ) ) ) {
433 0 : FD_LOG_WARNING(( "misaligned banks" ));
434 0 : return NULL;
435 0 : }
436 :
437 591 : if( FD_UNLIKELY( banks_data->magic!=FD_BANKS_MAGIC ) ) {
438 0 : FD_LOG_WARNING(( "Invalid banks magic" ));
439 0 : return NULL;
440 0 : }
441 :
442 591 : ulong expected_stake_accounts = fd_ulong_min( banks_data->max_stake_accounts, FD_RUNTIME_EXPECTED_STAKE_ACCOUNTS );
443 591 : ulong expected_vote_accounts = fd_ulong_min( banks_data->max_vote_accounts, FD_RUNTIME_EXPECTED_VOTE_ACCOUNTS );
444 :
445 591 : FD_SCRATCH_ALLOC_INIT( l, banks_data );
446 591 : banks_data = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_align(), sizeof(fd_banks_t) );
447 591 : void * stake_delegations_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_delegations_align(), fd_stake_delegations_footprint( banks_data->max_stake_accounts, expected_stake_accounts, banks_data->max_total_banks ) );
448 591 : void * epoch_leaders_mem = FD_SCRATCH_ALLOC_APPEND( l, FD_EPOCH_LEADERS_ALIGN, 2UL * banks_data->epoch_leaders_footprint );
449 591 : void * pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_pool_align(), fd_banks_pool_footprint( banks_data->max_total_banks ) );
450 591 : void * dead_banks_deque_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_banks_dead_align(), fd_banks_dead_footprint() );
451 591 : void * cost_tracker_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_bank_cost_tracker_pool_align(), fd_bank_cost_tracker_pool_footprint( banks_data->max_fork_width ) );
452 591 : void * stake_rewards_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_stake_rewards_align(), fd_stake_rewards_footprint( banks_data->max_stake_accounts, expected_stake_accounts, banks_data->max_fork_width ) );
453 591 : void * vote_stakes_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_vote_stakes_align(), fd_vote_stakes_footprint( banks_data->max_vote_accounts, expected_vote_accounts, banks_data->max_fork_width ) );
454 591 : void * new_votes_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_new_votes_align(), fd_new_votes_footprint( banks_data->max_vote_accounts, expected_vote_accounts, banks_data->max_total_banks ) );
455 591 : void * epoch_credits_mem = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_epoch_credits_t), sizeof(fd_epoch_credits_t) * banks_data->max_vote_accounts );
456 591 : void * snapshot_commission = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_stashed_commission_t), sizeof(fd_stashed_commission_t) * banks_data->max_vote_accounts );
457 0 : (void)new_votes_mem;
458 591 : (void)epoch_credits_mem;
459 591 : (void)snapshot_commission;
460 :
461 591 : FD_SCRATCH_ALLOC_FINI( l, fd_banks_align() );
462 :
463 591 : fd_bank_t * banks_pool = fd_banks_get_bank_pool( banks_data );
464 591 : if( FD_UNLIKELY( !banks_pool ) ) {
465 0 : FD_LOG_WARNING(( "Failed to join bank pool" ));
466 0 : return NULL;
467 0 : }
468 :
469 591 : if( FD_UNLIKELY( banks_pool!=fd_banks_pool_join( pool_mem ) ) ) {
470 0 : FD_LOG_WARNING(( "Failed to join bank pool" ));
471 0 : return NULL;
472 0 : }
473 :
474 591 : fd_bank_idx_seq_t * banks_dead_deque = fd_banks_dead_join( dead_banks_deque_mem );
475 591 : if( FD_UNLIKELY( !banks_dead_deque ) ) {
476 0 : FD_LOG_WARNING(( "Failed to join banks dead deque" ));
477 0 : return NULL;
478 0 : }
479 :
480 591 : if( FD_UNLIKELY( epoch_leaders_mem!=fd_banks_get_epoch_leaders( banks_data ) ) ) {
481 0 : FD_LOG_WARNING(( "Failed to join epoch leaders mem" ));
482 0 : return NULL;
483 0 : }
484 :
485 591 : if( FD_UNLIKELY( stake_delegations_mem!=fd_banks_get_stake_delegations( banks_data ) ) ) {
486 0 : FD_LOG_WARNING(( "Failed to join stake delegations root mem" ));
487 0 : return NULL;
488 0 : }
489 :
490 591 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks_data );
491 591 : if( FD_UNLIKELY( !cost_tracker_pool ) ) {
492 0 : FD_LOG_WARNING(( "Failed to join cost tracker pool" ));
493 0 : return NULL;
494 0 : }
495 :
496 591 : if( FD_UNLIKELY( cost_tracker_pool!=fd_bank_cost_tracker_pool_join( cost_tracker_pool_mem ) ) ) {
497 0 : FD_LOG_WARNING(( "Failed to join cost tracker pool" ));
498 0 : return NULL;
499 0 : }
500 :
501 591 : if( FD_UNLIKELY( !fd_stake_rewards_join( stake_rewards_mem ) ) ) {
502 0 : FD_LOG_WARNING(( "Failed to join stake rewards" ));
503 0 : return NULL;
504 0 : }
505 :
506 591 : if( FD_UNLIKELY( !fd_vote_stakes_join( vote_stakes_mem ) ) ) {
507 0 : FD_LOG_WARNING(( "Failed to join vote stakes" ));
508 0 : return NULL;
509 0 : }
510 :
511 591 : return banks_data;
512 591 : }
513 :
514 : fd_bank_t *
515 3990 : fd_banks_init_bank( fd_banks_t * banks ) {
516 :
517 3990 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
518 3990 : FD_CRIT( fd_banks_pool_free( bank_pool )!=0UL, "invariant violation: no free bank pool elements" );
519 :
520 3990 : fd_bank_t * bank = fd_banks_pool_ele_acquire( bank_pool );
521 3990 : bank->bank_seq = FD_ATOMIC_FETCH_AND_ADD( &banks->bank_seq, 1UL );
522 :
523 3990 : ulong null_idx = fd_banks_pool_idx_null( bank_pool );
524 3990 : bank->idx = fd_banks_pool_idx( bank_pool, bank );
525 3990 : bank->next = null_idx;
526 3990 : bank->parent_idx = null_idx;
527 3990 : bank->child_idx = null_idx;
528 3990 : bank->sibling_idx = null_idx;
529 :
530 3990 : fd_memset( &bank->f, 0, sizeof(bank->f) );
531 3990 : bank->stake_rewards_fork_id = UCHAR_MAX;
532 3990 : bank->stake_delegations_fork_id = USHORT_MAX;
533 3990 : bank->new_votes_fork_id = USHORT_MAX;
534 3990 : bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( fd_banks_get_cost_tracker_pool( banks ) );
535 3990 : bank->first_fec_set_received_nanos = fd_log_wallclock();
536 3990 : bank->preparation_begin_nanos = 0L;
537 3990 : bank->first_transaction_scheduled_nanos = 0L;
538 3990 : bank->last_transaction_finished_nanos = 0L;
539 3990 : bank->block_completed_nanos = 0L;
540 :
541 3990 : fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
542 3990 : bank->vote_stakes_fork_id = fd_vote_stakes_get_root_idx( vote_stakes );
543 :
544 3990 : bank->state = FD_BANK_STATE_FROZEN;
545 3990 : bank->refcnt = 0UL;
546 :
547 3990 : banks->root_idx = bank->idx;
548 :
549 3990 : FD_LOG_DEBUG(( "init bank (idx=%lu, vote_stakes_idx=%u, stake_rewards_idx=%u, stake_delegations_idx=%u, new_votes_idx=%u)",
550 3990 : bank->idx,
551 3990 : bank->vote_stakes_fork_id,
552 3990 : bank->stake_rewards_fork_id,
553 3990 : bank->stake_delegations_fork_id,
554 3990 : bank->new_votes_fork_id ));
555 :
556 3990 : return bank;
557 3990 : }
558 :
559 : fd_bank_t *
560 : fd_banks_clone_from_parent( fd_banks_t * banks,
561 3681 : ulong child_bank_idx ) {
562 :
563 3681 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
564 3681 : fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_bank_idx );
565 3681 : FD_CRIT( child_bank->state==FD_BANK_STATE_INIT, "invariant violation: bank is not initialized" );
566 :
567 3681 : fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, child_bank->parent_idx );
568 3681 : FD_CRIT( parent_bank->state==FD_BANK_STATE_FROZEN, "invariant violation: parent bank is not frozen" );
569 :
570 3681 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
571 3681 : FD_CRIT( fd_bank_cost_tracker_pool_free( cost_tracker_pool )!=0UL, "invariant violation: no free cost tracker pool elements" );
572 3681 : child_bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_acquire( cost_tracker_pool );
573 :
574 3681 : fd_memcpy( child_bank->top_votes_t_1_mem, parent_bank->top_votes_t_1_mem, FD_TOP_VOTES_MAX_FOOTPRINT );
575 3681 : fd_memcpy( child_bank->top_votes_t_2_mem, parent_bank->top_votes_t_2_mem, FD_TOP_VOTES_MAX_FOOTPRINT );
576 :
577 3681 : child_bank->f = parent_bank->f;
578 3681 : child_bank->vote_stakes_fork_id = parent_bank->vote_stakes_fork_id;
579 3681 : child_bank->stake_rewards_fork_id = parent_bank->stake_rewards_fork_id;
580 3681 : child_bank->stake_delegations_fork_id = fd_stake_delegations_new_fork( fd_banks_get_stake_delegations( banks ) );
581 3681 : child_bank->new_votes_fork_id = fd_new_votes_new_fork( fd_banks_get_new_votes( banks ) );
582 3681 : child_bank->f.block_height = parent_bank->f.block_height + 1UL;
583 3681 : child_bank->f.tick_height = parent_bank->f.max_tick_height;
584 3681 : child_bank->f.parent_slot = parent_bank->f.slot;
585 3681 : child_bank->f.parent_signature_cnt = parent_bank->f.signature_count;
586 3681 : child_bank->f.prev_bank_hash = parent_bank->f.bank_hash;
587 3681 : child_bank->f.execution_fees = 0UL;
588 3681 : child_bank->f.priority_fees = 0UL;
589 3681 : child_bank->f.tips = 0UL;
590 3681 : child_bank->f.signature_count = 0UL;
591 3681 : child_bank->f.total_compute_units_used = 0UL;
592 3681 : child_bank->f.shred_cnt = 0UL;
593 3681 : child_bank->f.txn_count = 0UL;
594 3681 : child_bank->f.nonvote_txn_count = 0UL;
595 3681 : child_bank->f.failed_txn_count = 0UL;
596 3681 : child_bank->f.nonvote_failed_txn_count = 0UL;
597 3681 : child_bank->f.identity_vote_idx = ULONG_MAX;
598 :
599 3681 : child_bank->state = FD_BANK_STATE_REPLAYABLE;
600 :
601 3681 : FD_LOG_DEBUG(( "cloning bank (idx=%lu, parent_idx=%lu, vote_stakes_idx=%u, stake_rewards_idx=%u, stake_delegations_idx=%u, new_votes_idx=%u)",
602 3681 : child_bank_idx,
603 3681 : parent_bank->idx,
604 3681 : child_bank->vote_stakes_fork_id,
605 3681 : child_bank->stake_rewards_fork_id,
606 3681 : child_bank->stake_delegations_fork_id,
607 3681 : child_bank->new_votes_fork_id ));
608 :
609 3681 : return child_bank;
610 3681 : }
611 :
612 : /* fd_bank_stake_delegation_apply_deltas applies all of the stake
613 : delegations for the entire direct ancestry from the bank to the
614 : root into a full fd_stake_delegations_t object. */
615 :
616 : static inline void
617 : fd_bank_apply_deltas( fd_banks_t * banks,
618 84 : fd_bank_t * bank ) {
619 :
620 84 : fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
621 84 : fd_new_votes_t * new_votes = fd_banks_get_new_votes( banks );
622 :
623 : /* The stake_delegations root has crossed an epoch boundary. The
624 : stake totals for the current root need to be updated. */
625 84 : fd_bank_t * old_root = fd_banks_root( banks );
626 84 : if( old_root->f.epoch!=bank->f.epoch ) {
627 12 : stake_delegations->effective_stake = bank->f.total_effective_stake;
628 12 : stake_delegations->activating_stake = bank->f.total_activating_stake;
629 12 : stake_delegations->deactivating_stake = bank->f.total_deactivating_stake;
630 12 : fd_new_votes_reset_root( new_votes );
631 12 : }
632 :
633 : /* Naively what we want to do is iterate from the old root to the new
634 : root and apply the delta to the full state iteratively. */
635 :
636 : /* First, gather all of the pool indicies that we want to apply deltas
637 : for in reverse order starting from the new root. We want to exclude
638 : the old root since its delta has been applied previously. */
639 84 : ushort sd_pool_indices[ banks->max_total_banks ];
640 84 : ushort nv_pool_indices[ banks->max_total_banks ];
641 84 : ulong pool_indices_len = 0UL;
642 :
643 84 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
644 :
645 84 : fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, bank->idx );
646 252 : while( !!curr_bank ) {
647 168 : FD_LOG_DEBUG(( "applying bank delta (bank_idx=%lu, sd_fork_idx=%u, nv_fork_idx=%u)", curr_bank->idx, curr_bank->stake_delegations_fork_id, curr_bank->new_votes_fork_id ));
648 168 : if( curr_bank->stake_delegations_fork_id!=USHORT_MAX ) {
649 90 : sd_pool_indices[pool_indices_len] = curr_bank->stake_delegations_fork_id;
650 90 : nv_pool_indices[pool_indices_len] = curr_bank->new_votes_fork_id;
651 90 : pool_indices_len++;
652 90 : }
653 168 : curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->parent_idx );
654 168 : }
655 :
656 : /* We have populated all of the indicies that we need to apply deltas
657 : from in reverse order. */
658 :
659 84 : fd_stake_history_t stake_history_[1];
660 84 : fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history_ );
661 : /* stake_history may be NULL */
662 174 : for( ulong i=pool_indices_len; i>0; i-- ) {
663 90 : ushort sd_idx = sd_pool_indices[i-1UL];
664 90 : ushort nv_idx = nv_pool_indices[i-1UL];
665 90 : fd_stake_delegations_apply_fork_delta( bank->f.epoch, stake_history, &bank->f.warmup_cooldown_rate_epoch, stake_delegations, sd_idx );
666 90 : fd_new_votes_apply_delta( new_votes, nv_idx );
667 90 : }
668 84 : }
669 :
670 : static inline void
671 : fd_bank_stake_delegation_mark_deltas( fd_banks_t * banks,
672 : fd_bank_t * bank,
673 165 : fd_stake_delegations_t * stake_delegations ) {
674 :
675 165 : ushort pool_indices[ banks->max_total_banks ];
676 165 : ulong pool_indices_len = 0UL;
677 :
678 165 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
679 :
680 165 : fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, bank->idx );
681 507 : while( !!curr_bank ) {
682 342 : if( curr_bank->stake_delegations_fork_id!=USHORT_MAX ) {
683 198 : pool_indices[pool_indices_len++] = curr_bank->stake_delegations_fork_id;
684 198 : }
685 342 : curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->parent_idx );
686 342 : }
687 :
688 165 : fd_stake_history_t stake_history[1];
689 165 : fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history );
690 :
691 363 : for( ulong i=pool_indices_len; i>0; i-- ) {
692 198 : ushort idx = pool_indices[i-1UL];
693 198 : fd_stake_delegations_mark_delta( stake_delegations, bank->f.epoch, stake_history, &bank->f.warmup_cooldown_rate_epoch, idx );
694 198 : }
695 165 : }
696 :
697 : static inline void
698 : fd_bank_stake_delegation_unmark_deltas( fd_banks_t * banks,
699 : fd_bank_t * bank,
700 165 : fd_stake_delegations_t * stake_delegations ) {
701 :
702 165 : ushort pool_indices[ banks->max_total_banks ];
703 165 : ulong pool_indices_len = 0UL;
704 :
705 165 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
706 :
707 165 : fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, bank->idx );
708 507 : while( !!curr_bank ) {
709 342 : if( curr_bank->stake_delegations_fork_id!=USHORT_MAX ) {
710 198 : pool_indices[pool_indices_len++] = curr_bank->stake_delegations_fork_id;
711 198 : }
712 342 : curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->parent_idx );
713 342 : }
714 :
715 165 : fd_stake_history_t stake_history_[1];
716 165 : fd_stake_history_t * stake_history = fd_sysvar_cache_stake_history_view( &bank->f.sysvar_cache, stake_history_ );
717 :
718 363 : for( ulong i=pool_indices_len; i>0; i-- ) {
719 198 : ushort idx = pool_indices[i-1UL];
720 198 : fd_stake_delegations_unmark_delta( stake_delegations, bank->f.epoch-1UL, stake_history, &bank->f.warmup_cooldown_rate_epoch, idx );
721 198 : }
722 165 : }
723 :
724 :
725 : fd_stake_delegations_t *
726 : fd_bank_stake_delegations_frontier_query( fd_banks_t * banks,
727 165 : fd_bank_t * bank ) {
728 165 : fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
729 165 : fd_bank_stake_delegation_mark_deltas( banks, bank, stake_delegations );
730 :
731 165 : return stake_delegations;
732 165 : }
733 :
734 : void
735 : fd_bank_stake_delegations_end_frontier_query( fd_banks_t * banks,
736 165 : fd_bank_t * bank ) {
737 165 : fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
738 165 : fd_bank_stake_delegation_unmark_deltas( banks, bank, stake_delegations );
739 165 : }
740 :
741 :
742 : fd_stake_delegations_t *
743 3435 : fd_banks_stake_delegations_root_query( fd_banks_t * banks ) {
744 3435 : return fd_banks_get_stake_delegations( banks );
745 3435 : }
746 :
747 : ulong
748 : fd_banks_new_votes_fork_indices( fd_bank_t * bank,
749 141 : ushort * fork_indices_out ) {
750 141 : fd_banks_t * banks = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
751 141 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
752 141 : ulong cnt = 0UL;
753 :
754 141 : fd_bank_t * curr = fd_banks_pool_ele( bank_pool, bank->idx );
755 429 : while( !!curr ) {
756 288 : if( curr->new_votes_fork_id!=USHORT_MAX ) {
757 147 : fork_indices_out[cnt++] = curr->new_votes_fork_id;
758 147 : }
759 288 : curr = fd_banks_pool_ele( bank_pool, curr->parent_idx );
760 288 : }
761 141 : return cnt;
762 141 : }
763 :
764 : void
765 : fd_banks_advance_root( fd_banks_t * banks,
766 84 : ulong root_bank_idx ) {
767 :
768 84 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
769 :
770 : /* We want to replace the old root with the new root. This means we
771 : have to remove banks that aren't descendants of the new root. */
772 :
773 84 : fd_bank_t * old_root = fd_banks_root( banks );
774 84 : FD_CRIT( old_root->refcnt==0UL, "refcnt for old root bank is nonzero" );
775 :
776 84 : fd_bank_t * new_root = fd_banks_pool_ele( bank_pool, root_bank_idx );
777 :
778 84 : fd_bank_apply_deltas( banks, new_root );
779 :
780 84 : fd_new_votes_t * new_votes = fd_banks_get_new_votes( banks );
781 84 : fd_new_votes_evict_fork( new_votes, new_root->new_votes_fork_id );
782 84 : new_root->new_votes_fork_id = USHORT_MAX;
783 :
784 84 : fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
785 84 : fd_stake_delegations_evict_fork( stake_delegations, new_root->stake_delegations_fork_id );
786 84 : new_root->stake_delegations_fork_id = USHORT_MAX;
787 :
788 : /* Now that the deltas have been applied, we can remove all nodes
789 : that are not direct descendants of the new root. */
790 84 : fd_bank_t * head = fd_banks_pool_ele( bank_pool, old_root->idx );
791 84 : head->next = ULONG_MAX;
792 84 : fd_bank_t * tail = head;
793 :
794 219 : while( head ) {
795 135 : fd_bank_t * child = fd_banks_pool_ele( bank_pool, head->child_idx );
796 :
797 270 : while( FD_LIKELY( child ) ) {
798 :
799 135 : if( FD_LIKELY( child!=new_root ) ) {
800 51 : if( FD_UNLIKELY( child->refcnt!=0UL ) ) {
801 0 : FD_LOG_CRIT(( "refcnt for child bank at index %lu is %lu", child->idx, child->refcnt ));
802 0 : }
803 :
804 : /* Update tail pointers */
805 51 : tail->next = child->idx;
806 51 : tail = fd_banks_pool_ele( bank_pool, tail->next );
807 51 : tail->next = fd_banks_pool_idx_null( bank_pool );
808 51 : }
809 :
810 135 : child = fd_banks_pool_ele( bank_pool, child->sibling_idx );
811 135 : }
812 :
813 135 : fd_bank_t * next = fd_banks_pool_ele( bank_pool, head->next );
814 :
815 : /* It is possible for a bank that never finished replaying to be
816 : pruned away. If the bank was never frozen, then it's possible
817 : that the bank still owns a cost tracker pool element. If this
818 : is the case, we need to release the pool element. */
819 135 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
820 135 : if( head->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) ) {
821 9 : FD_LOG_DEBUG(( "releasing cost tracker pool element for bank at index %lu", head->idx ));
822 9 : fd_bank_cost_tracker_pool_idx_release( cost_tracker_pool, head->cost_tracker_pool_idx );
823 9 : head->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool );
824 9 : }
825 :
826 135 : head->stake_rewards_fork_id = UCHAR_MAX;
827 135 : head->vote_stakes_fork_id = USHORT_MAX;
828 :
829 135 : if( head->new_votes_fork_id!=USHORT_MAX ) {
830 48 : FD_LOG_DEBUG(( "evicting new votes fork (bank_idx=%lu, fork_idx=%u)", head->idx, head->new_votes_fork_id ));
831 48 : fd_new_votes_evict_fork( new_votes, head->new_votes_fork_id );
832 48 : head->new_votes_fork_id = USHORT_MAX;
833 48 : }
834 :
835 135 : if( head->stake_delegations_fork_id!=USHORT_MAX ) {
836 51 : FD_LOG_DEBUG(( "evicting stake delegation fork (bank_idx=%lu, fork_idx=%u)", head->idx, head->stake_delegations_fork_id ));
837 51 : fd_stake_delegations_evict_fork( stake_delegations, head->stake_delegations_fork_id );
838 51 : head->stake_delegations_fork_id = USHORT_MAX;
839 51 : }
840 :
841 135 : head->state = FD_BANK_STATE_INACTIVE;
842 135 : fd_banks_pool_ele_release( bank_pool, head );
843 135 : head = next;
844 135 : }
845 :
846 : /* new_root is detached from old_root and becomes the only root.
847 : Clear sibling_idx too so traversals cannot follow a stale link to
848 : a bank index that was just pruned and later reused. */
849 84 : new_root->parent_idx = ULONG_MAX;
850 84 : new_root->sibling_idx = ULONG_MAX;
851 84 : banks->root_idx = new_root->idx;
852 :
853 84 : fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
854 84 : fd_vote_stakes_advance_root( vote_stakes, new_root->vote_stakes_fork_id );
855 84 : }
856 :
857 : /* Is the fork tree starting at the given bank entirely eligible for
858 : pruning? Returns 1 for yes, 0 for no.
859 :
860 : See comment in fd_replay_tile.c for more details on safe pruning. */
861 : static int
862 : fd_banks_subtree_can_be_pruned( fd_bank_t * bank_pool,
863 27 : fd_bank_t * bank ) {
864 :
865 27 : if( bank->refcnt!=0UL ) return 0;
866 :
867 : /* Recursively check all children. */
868 24 : ulong child_idx = bank->child_idx;
869 33 : while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
870 9 : fd_bank_t * child = fd_banks_pool_ele( bank_pool, child_idx );
871 9 : if( !fd_banks_subtree_can_be_pruned( bank_pool, child ) ) return 0;
872 9 : child_idx = child->sibling_idx;
873 9 : }
874 :
875 24 : return 1;
876 24 : }
877 :
878 : int
879 : fd_banks_advance_root_prepare( fd_banks_t * banks,
880 : ulong target_bank_idx,
881 15 : ulong * advanceable_bank_idx_out ) {
882 : /* TODO: An optimization here is to do a single traversal of the tree
883 : that would mark minority forks as dead while accumulating
884 : refcnts to determine which bank is the highest advanceable. */
885 :
886 15 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
887 :
888 15 : fd_bank_t * root = fd_banks_root( banks );
889 :
890 : /* Early exit if target is the same as the old root. */
891 15 : if( FD_UNLIKELY( root->idx==target_bank_idx ) ) {
892 0 : FD_LOG_WARNING(( "target bank_idx %lu is the same as the old root's bank index %lu", target_bank_idx, root->idx ));
893 0 : return 0;
894 0 : }
895 :
896 : /* Early exit if the root bank still has a reference to it, we can't
897 : advance from it unti it's released. */
898 15 : if( FD_UNLIKELY( root->refcnt!=0UL ) ) {
899 0 : return 0;
900 0 : }
901 :
902 15 : fd_bank_t * target_bank = fd_banks_pool_ele( bank_pool, target_bank_idx );
903 :
904 : /* Walk from target_bank up to root, recording the direct child of
905 : root on the path (prev). We only advance root by one level. */
906 :
907 15 : fd_bank_t * curr = target_bank;
908 15 : fd_bank_t * prev = NULL;
909 57 : while( curr && curr!=root ) {
910 42 : prev = curr;
911 42 : curr = fd_banks_pool_ele( bank_pool, curr->parent_idx );
912 42 : }
913 :
914 : /* If we didn't reach the old root or there is no parent, target is
915 : not a descendant. */
916 15 : if( FD_UNLIKELY( !curr || prev->parent_idx!=root->idx ) ) {
917 0 : FD_LOG_CRIT(( "invariant violation: target bank_idx %lu is not a direct descendant of root bank_idx %lu %lu %lu", target_bank_idx, root->idx, prev->idx, prev->parent_idx ));
918 0 : }
919 :
920 : /* We will at most advance our root bank by one. This means we can
921 : advance our root bank by one if each of the siblings of the
922 : potential new root are eligible for pruning. Each of the sibling
923 : subtrees can be pruned if the subtrees have no active references on
924 : their bank. */
925 15 : ulong advance_candidate_idx = prev->idx;
926 15 : ulong child_idx = root->child_idx;
927 42 : while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
928 30 : fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_idx );
929 30 : if( child_idx!=advance_candidate_idx ) {
930 18 : if( !fd_banks_subtree_can_be_pruned( bank_pool, child_bank ) ) {
931 3 : return 0;
932 3 : }
933 18 : }
934 27 : child_idx = child_bank->sibling_idx;
935 27 : }
936 :
937 12 : *advanceable_bank_idx_out = advance_candidate_idx;
938 12 : return 1;
939 15 : }
940 :
941 : fd_bank_t *
942 : fd_banks_new_bank( fd_banks_t * banks,
943 : ulong parent_bank_idx,
944 3705 : long now ) {
945 :
946 3705 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
947 3705 : FD_CRIT( fd_banks_pool_free( bank_pool )!=0UL, "invariant violation: no free bank indices available" );
948 :
949 3705 : ulong child_bank_idx = fd_banks_pool_idx_acquire( bank_pool );
950 3705 : fd_bank_t * child_bank = fd_banks_pool_ele( bank_pool, child_bank_idx );
951 3705 : FD_CRIT( child_bank->state==FD_BANK_STATE_INACTIVE, "invariant violation: bank for bank index is already initialized" );
952 :
953 3705 : ulong null_idx = fd_banks_pool_idx_null( bank_pool );
954 :
955 3705 : child_bank->bank_seq = FD_ATOMIC_FETCH_AND_ADD( &banks->bank_seq, 1UL );
956 3705 : child_bank->parent_idx = null_idx;
957 3705 : child_bank->child_idx = null_idx;
958 3705 : child_bank->sibling_idx = null_idx;
959 3705 : child_bank->next = null_idx;
960 3705 : child_bank->state = FD_BANK_STATE_INIT;
961 3705 : child_bank->refcnt = 0UL;
962 :
963 3705 : child_bank->stake_delegations_fork_id = USHORT_MAX;
964 3705 : child_bank->new_votes_fork_id = USHORT_MAX;
965 :
966 : /* Then make sure that the parent bank is valid and frozen. */
967 :
968 3705 : fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, parent_bank_idx );
969 3705 : FD_CRIT( parent_bank->state!=FD_BANK_STATE_INACTIVE && parent_bank->state!=FD_BANK_STATE_DEAD, "invariant violation: parent bank is dead or inactive" );
970 :
971 : /* Link node->parent */
972 3705 : child_bank->parent_idx = parent_bank_idx;
973 : /* Link parent->node and sibling->node */
974 3705 : if( FD_LIKELY( parent_bank->child_idx==null_idx ) ) {
975 : /* This is the first child so set as left-most child */
976 3627 : parent_bank->child_idx = child_bank_idx;
977 :
978 3627 : } else {
979 : /* Already have children so iterate to right-most sibling. */
980 78 : fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
981 105 : while( curr_bank->sibling_idx != null_idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
982 : /* Link to right-most sibling. */
983 78 : curr_bank->sibling_idx = child_bank_idx;
984 78 : }
985 :
986 3705 : child_bank->first_fec_set_received_nanos = now;
987 3705 : child_bank->first_transaction_scheduled_nanos = 0L;
988 3705 : child_bank->last_transaction_finished_nanos = 0L;
989 :
990 3705 : return child_bank;
991 3705 : }
992 :
993 : /* Mark everything in the fork tree starting at the given bank dead. */
994 :
995 : static ulong
996 : fd_banks_subtree_mark_dead( fd_banks_t * banks,
997 : fd_bank_t * bank_pool,
998 : fd_bank_t * bank,
999 33 : ulong * opt_idxs ) {
1000 33 : if( FD_UNLIKELY( !bank ) ) FD_LOG_CRIT(( "invariant violation: bank is NULL" ));
1001 :
1002 33 : ulong idxs_cnt = 0UL;
1003 33 : bank->state = FD_BANK_STATE_DEAD;
1004 33 : fd_banks_dead_push_head( fd_banks_get_dead_banks_deque( banks ), (fd_bank_idx_seq_t){ .idx = bank->idx, .seq = bank->bank_seq } );
1005 33 : if( opt_idxs ) opt_idxs[ idxs_cnt ] = bank->idx;
1006 33 : idxs_cnt++;
1007 :
1008 : /* Recursively mark all children as dead. */
1009 33 : ulong child_idx = bank->child_idx;
1010 42 : while( child_idx!=fd_banks_pool_idx_null( bank_pool ) ) {
1011 9 : fd_bank_t * child = fd_banks_pool_ele( bank_pool, child_idx );
1012 9 : ulong * child_idxs = opt_idxs ? opt_idxs+idxs_cnt : NULL;
1013 9 : idxs_cnt += fd_banks_subtree_mark_dead( banks, bank_pool, child, child_idxs );
1014 9 : child_idx = child->sibling_idx;
1015 9 : }
1016 :
1017 33 : return idxs_cnt;
1018 33 : }
1019 :
1020 : void
1021 : fd_banks_mark_bank_dead( fd_banks_t * banks,
1022 : ulong bank_idx,
1023 : ulong * opt_idxs,
1024 24 : ulong * opt_idxs_cnt ) {
1025 24 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
1026 24 : fd_bank_t * bank = fd_banks_pool_ele( bank_pool, bank_idx );
1027 :
1028 24 : ulong idxs_cnt = fd_banks_subtree_mark_dead( banks, bank_pool, bank, opt_idxs );
1029 24 : if( opt_idxs_cnt ) *opt_idxs_cnt = idxs_cnt;
1030 24 : }
1031 :
1032 : int
1033 : fd_banks_prune_one_dead_bank( fd_banks_t * banks,
1034 51 : fd_banks_prune_cancel_info_t * cancel ) {
1035 51 : fd_bank_idx_seq_t * dead_banks_queue = fd_banks_get_dead_banks_deque( banks );
1036 51 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
1037 51 : ulong null_idx = fd_banks_pool_idx_null( bank_pool );
1038 54 : while( !fd_banks_dead_empty( dead_banks_queue ) ) {
1039 33 : fd_bank_idx_seq_t * head = fd_banks_dead_peek_head( dead_banks_queue );
1040 33 : fd_bank_t * bank = fd_banks_pool_ele( bank_pool, head->idx );
1041 33 : if( bank->state==FD_BANK_STATE_INACTIVE || bank->bank_seq!=head->seq ) {
1042 3 : fd_banks_dead_pop_head( dead_banks_queue );
1043 3 : continue;
1044 30 : } else if( bank->refcnt!=0UL ) {
1045 3 : break;
1046 3 : }
1047 :
1048 27 : FD_LOG_DEBUG(( "pruning dead bank (idx=%lu)", bank->idx ));
1049 :
1050 27 : int started_replaying = bank->stake_delegations_fork_id!=USHORT_MAX;
1051 :
1052 : /* There are a few cases to consider:
1053 : 1. The to-be-pruned bank is the left-most child of the parent.
1054 : This means that the parent bank's child idx is the
1055 : to-be-pruned bank. In this case, we can simply make the
1056 : left-most sibling of the to-be-pruned bank the new left-most
1057 : child (set parent's banks child idx to the sibling). The
1058 : sibling pointer can be null if the to-be-pruned bank is an
1059 : only child of the parent.
1060 : 2. The to-be-pruned bank is some right child of the parent. In
1061 : this case, the child bank which has a sibling pointer to the
1062 : to-be-pruned bank needs to be updated to point to the sibling
1063 : of the to-be-pruned bank. The sibling can even be null if the
1064 : to-be-pruned bank is the right-most child of the parent.
1065 : */
1066 :
1067 27 : FD_TEST( bank->child_idx==null_idx );
1068 27 : fd_bank_t * parent_bank = fd_banks_pool_ele( bank_pool, bank->parent_idx );
1069 27 : if( parent_bank->child_idx==bank->idx ) {
1070 : /* Case 1: left-most child */
1071 12 : parent_bank->child_idx = bank->sibling_idx;
1072 15 : } else {
1073 : /* Case 2: some right child */
1074 15 : fd_bank_t * curr_bank = fd_banks_pool_ele( bank_pool, parent_bank->child_idx );
1075 21 : while( curr_bank->sibling_idx!=bank->idx ) curr_bank = fd_banks_pool_ele( bank_pool, curr_bank->sibling_idx );
1076 15 : curr_bank->sibling_idx = bank->sibling_idx;
1077 15 : }
1078 27 : bank->parent_idx = null_idx;
1079 27 : bank->sibling_idx = null_idx;
1080 :
1081 27 : if( FD_UNLIKELY( bank->cost_tracker_pool_idx!=null_idx ) ) {
1082 15 : fd_bank_cost_tracker_pool_idx_release( fd_banks_get_cost_tracker_pool( banks ), bank->cost_tracker_pool_idx );
1083 15 : bank->cost_tracker_pool_idx = null_idx;
1084 15 : }
1085 :
1086 27 : fd_stake_delegations_t * stake_delegations = fd_banks_get_stake_delegations( banks );
1087 27 : fd_stake_delegations_evict_fork( stake_delegations, bank->stake_delegations_fork_id );
1088 27 : bank->stake_delegations_fork_id = USHORT_MAX;
1089 :
1090 27 : fd_new_votes_t * new_votes = fd_banks_get_new_votes( banks );
1091 27 : fd_new_votes_evict_fork( new_votes, bank->new_votes_fork_id );
1092 27 : bank->new_votes_fork_id = USHORT_MAX;
1093 :
1094 27 : bank->stake_rewards_fork_id = UCHAR_MAX;
1095 :
1096 27 : if( FD_LIKELY( started_replaying ) ) {
1097 18 : cancel->txncache_fork_id = bank->txncache_fork_id;
1098 18 : cancel->slot = bank->f.slot;
1099 18 : cancel->bank_seq = bank->bank_seq;
1100 18 : cancel->bank_idx = bank->idx;
1101 18 : }
1102 :
1103 27 : bank->state = FD_BANK_STATE_INACTIVE;
1104 :
1105 27 : fd_banks_pool_ele_release( bank_pool, bank );
1106 27 : fd_banks_dead_pop_head( dead_banks_queue );
1107 27 : return 1+started_replaying;
1108 27 : }
1109 24 : return 0;
1110 51 : }
1111 :
1112 : void
1113 132 : fd_banks_mark_bank_frozen( fd_bank_t * bank ) {
1114 132 : fd_banks_t * banks = fd_type_pun( (uchar *)bank - bank->banks_data_offset );
1115 :
1116 132 : FD_CRIT( bank->state==FD_BANK_STATE_REPLAYABLE, "invariant violation: bank is not replayable" );
1117 132 : bank->state = FD_BANK_STATE_FROZEN;
1118 :
1119 132 : FD_CRIT( bank->cost_tracker_pool_idx!=ULONG_MAX, "invariant violation: cost tracker pool index is null" );
1120 132 : fd_bank_cost_tracker_pool_idx_release( fd_banks_get_cost_tracker_pool( banks ), bank->cost_tracker_pool_idx );
1121 132 : bank->cost_tracker_pool_idx = ULONG_MAX;
1122 132 : }
1123 :
1124 : static void
1125 : fd_banks_get_frontier_private( fd_bank_t * bank_pool,
1126 : ulong bank_idx,
1127 : ulong * frontier_indices_out,
1128 144 : ulong * frontier_cnt_out ) {
1129 144 : if( bank_idx==fd_banks_pool_idx_null( bank_pool ) ) return;
1130 :
1131 90 : fd_bank_t * bank = fd_banks_pool_ele( bank_pool, bank_idx );
1132 :
1133 90 : if( bank->child_idx==fd_banks_pool_idx_null( bank_pool ) ) {
1134 45 : if( bank->state!=FD_BANK_STATE_FROZEN && bank->state!=FD_BANK_STATE_DEAD ) {
1135 36 : frontier_indices_out[*frontier_cnt_out] = bank->idx;
1136 36 : (*frontier_cnt_out)++;
1137 36 : }
1138 45 : } else {
1139 45 : fd_banks_get_frontier_private( bank_pool, bank->child_idx, frontier_indices_out, frontier_cnt_out );
1140 45 : }
1141 90 : fd_banks_get_frontier_private( bank_pool, bank->sibling_idx, frontier_indices_out, frontier_cnt_out );
1142 90 : }
1143 :
1144 : void
1145 : fd_banks_get_frontier( fd_banks_t * banks,
1146 : ulong * frontier_indices_out,
1147 9 : ulong * frontier_cnt_out ) {
1148 9 : *frontier_cnt_out = 0UL;
1149 9 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
1150 9 : fd_banks_get_frontier_private( bank_pool, banks->root_idx, frontier_indices_out, frontier_cnt_out );
1151 9 : }
1152 :
1153 : void
1154 : fd_banks_clear_bank( fd_banks_t * banks,
1155 : fd_bank_t * bank,
1156 3 : ulong max_vote_accounts ) {
1157 :
1158 3 : fd_memset( &bank->f, 0, sizeof(bank->f) );
1159 :
1160 3 : fd_top_votes_init( fd_type_pun( bank->top_votes_t_1_mem ) );
1161 3 : fd_top_votes_init( fd_type_pun( bank->top_votes_t_2_mem ) );
1162 :
1163 : /* We need to acquire a cost tracker element. */
1164 3 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
1165 3 : if( FD_UNLIKELY( bank->cost_tracker_pool_idx!=fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool ) ) ) {
1166 3 : fd_bank_cost_tracker_pool_idx_release( cost_tracker_pool, bank->cost_tracker_pool_idx );
1167 3 : }
1168 3 : bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_acquire( cost_tracker_pool );
1169 :
1170 3 : if( FD_UNLIKELY( bank->new_votes_fork_id!=USHORT_MAX ) ) {
1171 3 : fd_new_votes_evict_fork( fd_banks_get_new_votes( banks ), bank->new_votes_fork_id );
1172 3 : bank->new_votes_fork_id = USHORT_MAX;
1173 3 : }
1174 :
1175 3 : fd_vote_stakes_t * vote_stakes = fd_banks_get_vote_stakes( banks );
1176 3 : fd_vote_stakes_new( vote_stakes, max_vote_accounts, max_vote_accounts, banks->max_fork_width, 999UL );
1177 3 : }
1178 :
1179 : void
1180 3438 : fd_banks_clear( fd_banks_t * banks ) {
1181 :
1182 3438 : fd_bank_t * bank_pool = fd_banks_get_bank_pool( banks );
1183 3438 : fd_bank_cost_tracker_t * cost_tracker_pool = fd_banks_get_cost_tracker_pool( banks );
1184 :
1185 58446 : for( ulong i=0UL; i<banks->max_total_banks; i++ ) {
1186 55008 : fd_bank_t * bank = fd_banks_pool_ele( bank_pool, i );
1187 55008 : bank->state = FD_BANK_STATE_INACTIVE;
1188 55008 : bank->cost_tracker_pool_idx = fd_bank_cost_tracker_pool_idx_null( cost_tracker_pool );
1189 55008 : bank->new_votes_fork_id = USHORT_MAX;
1190 55008 : }
1191 :
1192 3438 : fd_banks_pool_reset( bank_pool );
1193 3438 : fd_bank_cost_tracker_pool_reset( cost_tracker_pool );
1194 3438 : fd_banks_dead_remove_all( fd_banks_get_dead_banks_deque( banks ) );
1195 :
1196 3438 : fd_vote_stakes_reset( fd_banks_get_vote_stakes( banks ) );
1197 3438 : fd_new_votes_reset( fd_banks_get_new_votes( banks ) );
1198 3438 : fd_stake_delegations_reset( fd_banks_get_stake_delegations( banks ) );
1199 :
1200 3438 : fd_stake_rewards_clear( fd_banks_get_stake_rewards( banks ) );
1201 :
1202 : banks->root_idx = ULONG_MAX;
1203 3438 : banks->bank_seq = 0UL;
1204 3438 : }
|