Line data Source code
1 : /* Serialize a chunk of values.
2 : Each call may only produce up to FD_SSMANIFEST_BUF_MIN bytes worth of
3 : serialized data. Therefore, we split the serializer into multiple
4 : states. */
5 :
6 210 : ENCODE_FN {
7 210 : fd_bank_t const * bank = enc->bank;
8 :
9 210 : PREP
10 :
11 210 : switch( enc->state ) {
12 6 : case STATE_BLOCKHASH_QUEUE: {
13 3 : fd_blockhashes_t const * bhq = &bank->f.block_hash_queue;
14 3 : fd_blockhash_info_t const * deq = bhq->d.deque;
15 3 : ulong total = fd_blockhash_deq_cnt( deq );
16 6 : ulong to_write = fd_ulong_min( total, FD_BLOCKHASHES_MAX );
17 3 : ulong to_skip = total - to_write;
18 6 : PUSH_VAL( ulong, to_write-1UL ); /* last hash index */
19 3 : fd_hash_t const * last_hash = fd_blockhashes_peek_last_hash( bhq );
20 6 : PUSH_VAL( uchar, !!last_hash );
21 6 : if( last_hash ) PUSH_VAL( fd_hash_t, *last_hash );
22 :
23 6 : PUSH_VAL( ulong, to_write );
24 12 : for( ulong i=0UL; i<to_write; i++ ) {
25 6 : fd_blockhash_info_t const * ele = fd_blockhash_deq_peek_index_const( deq, to_skip+i );
26 6 : PUSH_VAL( fd_hash_t, ele->hash );
27 6 : PUSH_VAL( ulong, ele->lamports_per_signature );
28 6 : PUSH_VAL( ulong, i );
29 6 : PUSH_VAL( ulong, 0UL ); /* timestamp, ignored */
30 3 : }
31 6 : PUSH_VAL( ulong, FD_BLOCKHASHES_MAX-1UL ); /* max_age */
32 6 : enc->state = STATE_HASHES;
33 3 : break;
34 3 : }
35 6 : case STATE_HASHES: {
36 6 : PUSH_VAL( ulong, 0UL ); /* ancestors */
37 6 : PUSH_VAL( fd_hash_t, bank->f.bank_hash );
38 6 : PUSH_VAL( fd_hash_t, bank->f.prev_bank_hash );
39 6 : PUSH_VAL( ulong, bank->f.parent_slot );
40 6 : enc->state = STATE_HARD_FORKS;
41 3 : break;
42 3 : }
43 6 : case STATE_HARD_FORKS: {
44 6 : PUSH_VAL( ulong, bank->f.hard_fork_cnt );
45 6 : for( ulong i=0UL; i<bank->f.hard_fork_cnt; i++ ) {
46 0 : PUSH_VAL( ulong, bank->f.hard_forks[ i ].slot );
47 0 : PUSH_VAL( ulong, bank->f.hard_forks[ i ].cnt );
48 0 : }
49 6 : enc->state = STATE_COUNTERS;
50 3 : break;
51 3 : }
52 6 : case STATE_COUNTERS: {
53 6 : PUSH_VAL( ulong, bank->f.parent_txn_count + bank->f.txn_count );
54 6 : PUSH_VAL( ulong, bank->f.tick_height );
55 6 : PUSH_VAL( ulong, bank->f.signature_count );
56 6 : PUSH_VAL( ulong, bank->f.capitalization );
57 6 : PUSH_VAL( ulong, bank->f.max_tick_height );
58 6 : PUSH_VAL( uchar, 1 );
59 6 : PUSH_VAL( ulong, bank->f.slot_params.hashes_per_tick );
60 6 : PUSH_VAL( ulong, bank->f.ticks_per_slot );
61 6 : PUSH_VAL( fd_w_u128_t, (fd_w_u128_t){ .ud = bank->f.slot_params.ns_per_slot } );
62 6 : PUSH_VAL( ulong, bank->f.genesis_creation_time );
63 6 : PUSH_VAL( double, bank->f.slot_params.slots_per_year );
64 6 : PUSH_VAL( ulong, 0UL ); /* accounts_data_len, unused */
65 6 : PUSH_VAL( ulong, bank->f.slot );
66 6 : PUSH_VAL( ulong, bank->f.epoch );
67 6 : PUSH_VAL( ulong, bank->f.block_height );
68 6 : PUSH_VAL( fd_pubkey_t, (fd_pubkey_t){0} ); /* leader_id, unused */
69 6 : PUSH_VAL( ulong, 0UL ); /* unused_collector_fees */
70 6 : PUSH_VAL( ulong, 0UL ); /* unused_fee_calculator */
71 :
72 3 : fd_fee_rate_governor_t const * frg = &bank->f.fee_rate_governor;
73 6 : PUSH_VAL( ulong, frg->target_lamports_per_signature );
74 6 : PUSH_VAL( ulong, frg->target_signatures_per_slot );
75 6 : PUSH_VAL( ulong, frg->min_lamports_per_signature );
76 6 : PUSH_VAL( ulong, frg->max_lamports_per_signature );
77 6 : PUSH_VAL( uchar, frg->burn_percent );
78 6 : PUSH_VAL( ulong, 0UL );
79 6 : PUSH_VAL( ulong, bank->f.epoch );
80 :
81 3 : fd_epoch_schedule_t const * es = &bank->f.epoch_schedule;
82 3 : fd_rent_t const * rent = &bank->f.rent;
83 6 : PUSH_VAL( ulong, es->slots_per_epoch );
84 6 : PUSH_VAL( ulong, es->leader_schedule_slot_offset );
85 6 : PUSH_VAL( uchar, es->warmup );
86 6 : PUSH_VAL( ulong, es->first_normal_epoch );
87 6 : PUSH_VAL( ulong, es->first_normal_slot );
88 6 : PUSH_VAL( double, bank->f.slot_params.slots_per_year );
89 6 : PUSH_VAL( ulong, rent->lamports_per_uint8_year );
90 6 : PUSH_VAL( double, rent->exemption_threshold );
91 6 : PUSH_VAL( uchar, rent->burn_percent );
92 6 : PUSH_VAL( ulong, es->slots_per_epoch );
93 6 : PUSH_VAL( ulong, es->leader_schedule_slot_offset );
94 6 : PUSH_VAL( uchar, es->warmup );
95 6 : PUSH_VAL( ulong, es->first_normal_epoch );
96 6 : PUSH_VAL( ulong, es->first_normal_slot );
97 :
98 3 : fd_inflation_t const * inf = &bank->f.inflation;
99 6 : PUSH_VAL( double, inf->initial );
100 6 : PUSH_VAL( double, inf->terminal );
101 6 : PUSH_VAL( double, inf->taper );
102 6 : PUSH_VAL( double, inf->foundation );
103 6 : PUSH_VAL( double, inf->foundation_term );
104 6 : PUSH_VAL( double, inf->unused );
105 :
106 6 : enc->state = STATE_VOTE_ACCOUNTS;
107 3 : break;
108 3 : }
109 6 : case STATE_VOTE_ACCOUNTS: {
110 6 : PUSH_VAL( ulong, 0UL ); /* zero vote_accounts */
111 6 : PUSH_VAL( ulong, 0UL ); /* zero stake delegations */
112 6 : PUSH_VAL( ulong, 0UL ); /* unused */
113 6 : PUSH_VAL( ulong, bank->f.epoch );
114 6 : enc->state = STATE_STAKE_HISTORY;
115 3 : break;
116 3 : }
117 0 : case STATE_STAKE_DELEGATION: { FD_LOG_ERR(( "TODO")); }
118 0 : case STATE_STAKE_EPOCH: { FD_LOG_ERR(( "TODO")); }
119 6 : case STATE_STAKE_HISTORY: {
120 6 : PUSH_VAL( ulong, 0UL ); /* zero stake history entries */
121 6 : enc->state = STATE_BANK_TRAILER;
122 3 : break;
123 3 : }
124 6 : case STATE_BANK_TRAILER: {
125 6 : PUSH_VAL( ulong, 0UL ); /* unused_accounts.unused1 */
126 6 : PUSH_VAL( ulong, 0UL ); /* unused_accounts.unused2 */
127 6 : PUSH_VAL( ulong, 0UL ); /* unused_accounts.unused3 */
128 6 : PUSH_VAL( ulong, 0UL ); /* unused_epoch_stakes */
129 6 : PUSH_VAL( uchar, 0 ); /* is_delta */
130 6 : PUSH_VAL( ulong, 0UL ); /* zero account_storage_entries */
131 6 : enc->state = STATE_BANK_HASH_INFO;
132 3 : break;
133 3 : }
134 0 : case STATE_ACCOUNT_STORAGE_ENTRY: { FD_LOG_ERR(( "TODO")); }
135 6 : case STATE_BANK_HASH_INFO: {
136 : /* AccountsDbFields */
137 6 : PUSH_VAL( ulong, 0UL ); /* write_version, unused */
138 6 : PUSH_VAL( ulong, bank->f.slot ); /* slot */
139 6 : PUSH_VAL( fd_hash_t, (fd_hash_t){0} ); /* unused_accounts_delta_hash */
140 6 : PUSH_VAL( fd_hash_t, (fd_hash_t){0} ); /* unused_accounts_hash */
141 6 : PUSH_VAL( ulong, 0UL ); /* num_updated_accounts, unused */
142 6 : PUSH_VAL( ulong, 0UL ); /* num_removed_accounts, unused */
143 6 : PUSH_VAL( ulong, 0UL ); /* num_lamports_stored, unused */
144 6 : PUSH_VAL( ulong, 0UL ); /* total_data_len, unused */
145 6 : PUSH_VAL( ulong, 0UL ); /* num_executable_accounts, unused */
146 6 : PUSH_VAL( ulong, 0UL ); /* historical_roots, unused */
147 6 : PUSH_VAL( ulong, 0UL ); /* historical_roots_with_hash, unused */
148 : /* ExtraFieldsToSerialize */
149 6 : PUSH_VAL( ulong, bank->f.rbh_lamports_per_sig );
150 6 : PUSH_VAL( uchar, 0 ); /* unused_incremental_snapshot_persistence */
151 6 : PUSH_VAL( uchar, 0 ); /* unused_epoch_accounts_hash */
152 :
153 3 : ulong epoch = bank->f.epoch;
154 6 : ulong epoch_cnt = (epoch > 0UL) ? 3UL : 2UL;
155 6 : PUSH_VAL( ulong, epoch_cnt );
156 3 : enc->epoch_cnt = (uchar)epoch_cnt;
157 3 : enc->epoch_idx = 0;
158 6 : enc->state = STATE_EPOCH_STAKES;
159 3 : break;
160 3 : }
161 18 : case STATE_EPOCH_STAKES: {
162 9 : ulong epoch = bank->f.epoch;
163 18 : ulong epoch_stakes_base = (epoch > 0UL) ? (epoch - 1UL) : 0UL;
164 9 : ulong epoch_key = epoch_stakes_base + (ulong)enc->epoch_idx;
165 :
166 : /* entry_type: 0=T-3 commission, 1=T-2 stakes, 2=T-1 stakes+credits */
167 18 : uint entry_type = (epoch > 0UL) ? enc->epoch_idx : (uint)(enc->epoch_idx + 1U);
168 9 : fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
169 9 : ulong fork_id = bank->vote_stakes_fork_id;
170 :
171 9 : uint vote_cnt;
172 18 : if( entry_type==2U ) {
173 6 : vote_cnt = (uint)fd_vote_stakes_cnt_t_1( vote_stakes, fork_id );
174 6 : fd_vote_stakes_t_1_iter_init( vote_stakes, fork_id, enc->vote_stakes_iter_mem );
175 12 : } else if( entry_type==1U ) {
176 6 : vote_cnt = (uint)fd_vote_stakes_cnt_t_2( vote_stakes, fork_id );
177 6 : fd_vote_stakes_t_2_iter_init( vote_stakes, fork_id, enc->vote_stakes_iter_mem );
178 6 : } else {
179 6 : vote_cnt = (uint)*fd_bank_epoch_credits_len( enc->bank );
180 6 : }
181 9 : enc->vote_cnt = vote_cnt;
182 9 : enc->vote_idx = 0;
183 9 : enc->total_stake = 0UL;
184 :
185 18 : PUSH_VAL( ulong, epoch_key );
186 18 : PUSH_VAL( uint, 0U ); /* variant = 0 (VersionedEpochStakes::Current) */
187 18 : PUSH_VAL( ulong, (ulong)vote_cnt );
188 :
189 18 : enc->state = (vote_cnt > 0U) ? STATE_EPOCH_STAKES_STAKES : STATE_EPOCH_STAKES_EPOCH;
190 9 : break;
191 9 : }
192 54 : case STATE_EPOCH_STAKES_STAKES: {
193 54 : ulong epoch = bank->f.epoch;
194 54 : uint entry_type = (epoch > 0UL) ? enc->epoch_idx : (uint)(enc->epoch_idx + 1U);
195 :
196 54 : fd_pubkey_t pubkey = {0};
197 54 : ulong stake = 0UL;
198 54 : fd_pubkey_t node_account = {0};
199 54 : ushort commission = 0;
200 54 : ulong ec_cnt = 0UL;
201 54 : fd_epoch_credits_t const * ec = NULL;
202 :
203 54 : fd_collector_overrides_t * overrides = fd_bank_collector_overrides( bank );
204 54 : ushort co_root = fd_collector_overrides_get_root_idx( overrides );
205 54 : ulong co_epoch = ULONG_MAX; /* no collector lookup */
206 54 : fd_vote_stakes_t * vote_stakes = fd_bank_vote_stakes( bank );
207 54 : ulong fork_id = bank->vote_stakes_fork_id;
208 :
209 54 : if( entry_type==2U ) {
210 18 : fd_vote_stakes_t_1_iter_t * iter = fd_type_pun( enc->vote_stakes_iter_mem );
211 18 : FD_TEST( !fd_vote_stakes_t_1_iter_done( vote_stakes, fork_id, iter ) );
212 18 : fd_vote_stakes_t_1_iter_ele( vote_stakes, fork_id, iter, &pubkey, &node_account, &stake, &commission );
213 18 : ec = find_epoch_credits( enc->bank, &pubkey );
214 18 : FD_TEST( ec );
215 18 : ec_cnt = ec->cnt;
216 18 : co_epoch = bank->f.epoch;
217 36 : } else if( entry_type==1U ) {
218 18 : fd_vote_stakes_t_2_iter_t * iter = fd_type_pun( enc->vote_stakes_iter_mem );
219 18 : FD_TEST( !fd_vote_stakes_t_2_iter_done( vote_stakes, fork_id, iter ) );
220 18 : fd_vote_stakes_t_2_iter_ele( vote_stakes, fork_id, iter, &pubkey, &node_account, &stake, NULL, NULL, &commission, NULL );
221 18 : co_epoch = fd_ulong_sat_sub( bank->f.epoch, 1UL );
222 18 : } else {
223 : /* The bank epoch credits will have the resolved commission for
224 : the vote account. This means that the commission stored will
225 : be the t-3 commission if it existed or the t-2/t-1 commission
226 : otherwise as the fallback (see delay_commission_update feature
227 : for more details). This means that the serialized commission
228 : for the epoch may be inaccurate but the commission produced
229 : will still produce a correct commission for the purposes of
230 : rewards. That is to say that the commission for each vote
231 : account will be accurate. */
232 18 : ec = &fd_bank_epoch_credits( enc->bank )[ enc->vote_idx ];
233 18 : fd_memcpy( &pubkey, ec->pubkey, 32UL );
234 18 : commission = ec->commission;
235 18 : }
236 :
237 : /* SIMD-0232 collectors: defaults unless overridden. */
238 54 : fd_pubkey_t inflation_collector = {0};
239 27 : fd_pubkey_t block_collector = {0};
240 54 : if( FD_LIKELY( co_epoch!=ULONG_MAX ) ) {
241 36 : inflation_collector = pubkey;
242 36 : block_collector = node_account;
243 36 : fd_collector_overrides_query( overrides, co_root, co_epoch, &pubkey, &inflation_collector, &block_collector );
244 36 : }
245 :
246 27 : enc->total_stake += stake;
247 27 : ulong data_length = 186UL + 24UL * ec_cnt;
248 :
249 : /* Vote account key + stake */
250 54 : PUSH_VAL( fd_pubkey_t, pubkey );
251 54 : PUSH_VAL( ulong, stake );
252 :
253 : /* AccountSharedData: lamports, data_length */
254 54 : PUSH_VAL( ulong, 0UL );
255 54 : PUSH_VAL( ulong, data_length );
256 :
257 : /* VoteStateV4 */
258 54 : PUSH_VAL( uint, 3U ); /* variant = V4 */
259 54 : PUSH_VAL( fd_pubkey_t, node_account ); /* node_pubkey */
260 54 : PUSH_VAL( fd_pubkey_t, (fd_pubkey_t){0} ); /* authorized_withdrawer */
261 54 : PUSH_VAL( fd_pubkey_t, inflation_collector ); /* inflation_rewards_collector */
262 54 : PUSH_VAL( fd_pubkey_t, block_collector ); /* block_revenue_collector */
263 54 : PUSH_VAL( ushort, commission ); /* inflation_rewards_commission_bps */
264 54 : PUSH_VAL( ushort, (ushort)0 ); /* block_revenue_commission_bps */
265 54 : PUSH_VAL( ulong, 0UL ); /* pending_delegator_rewards */
266 54 : PUSH_VAL( uchar, 0 ); /* bls_pubkey_compressed = None */
267 54 : PUSH_VAL( ulong, 0UL ); /* votes_length = 0 */
268 54 : PUSH_VAL( uchar, 0 ); /* root_slot = None */
269 54 : PUSH_VAL( ulong, 0UL ); /* authorized_voters_length = 0 */
270 :
271 : /* Epoch credits */
272 54 : PUSH_VAL( ulong, ec_cnt );
273 108 : for( ulong j=0UL; j<ec_cnt; j++ ) {
274 54 : PUSH_VAL( ulong, (ulong)ec->epoch[j] );
275 54 : PUSH_VAL( ulong, ec->base_credits + (ulong)ec->credits_delta[j] );
276 54 : PUSH_VAL( ulong, ec->base_credits + (ulong)ec->prev_credits_delta[j] );
277 27 : }
278 :
279 54 : PUSH_VAL( ulong, 0UL ); /* last_timestamp_slot */
280 54 : PUSH_VAL( ulong, 0UL ); /* last_timestamp_timestamp */
281 :
282 : /* AccountSharedData trailer */
283 54 : PUSH_VAL( fd_pubkey_t, fd_solana_vote_program_id ); /* owner */
284 54 : PUSH_VAL( uchar, 1 ); /* executable */
285 54 : PUSH_VAL( ulong, 0UL ); /* rent_epoch */
286 :
287 27 : enc->vote_idx++;
288 54 : if( entry_type==2U ) {
289 18 : fd_vote_stakes_t_1_iter_next( vote_stakes, fork_id, fd_type_pun( enc->vote_stakes_iter_mem ) );
290 36 : } else if( entry_type==1U ) {
291 18 : fd_vote_stakes_t_2_iter_next( vote_stakes, fork_id, fd_type_pun( enc->vote_stakes_iter_mem ) );
292 18 : }
293 54 : if( enc->vote_idx >= enc->vote_cnt ) enc->state = STATE_EPOCH_STAKES_EPOCH;
294 27 : break;
295 27 : }
296 18 : case STATE_EPOCH_STAKES_EPOCH: {
297 9 : ulong epoch = bank->f.epoch;
298 18 : ulong epoch_stakes_base = (epoch > 0UL) ? (epoch - 1UL) : 0UL;
299 9 : ulong epoch_key = epoch_stakes_base + (ulong)enc->epoch_idx;
300 :
301 18 : PUSH_VAL( ulong, 0UL ); /* stake_delegations_length = 0 */
302 18 : PUSH_VAL( ulong, 0UL ); /* unused */
303 18 : PUSH_VAL( ulong, epoch_key ); /* epoch */
304 18 : PUSH_VAL( ulong, 0UL ); /* stake_history_length = 0 */
305 18 : enc->state = STATE_EPOCH_TOTAL_STAKE;
306 9 : break;
307 9 : }
308 0 : case STATE_EPOCH_STAKE_HISTORY: { __builtin_unreachable(); }
309 18 : case STATE_EPOCH_TOTAL_STAKE: {
310 18 : uint entry_type = (bank->f.epoch > 0UL) ? enc->epoch_idx : (uint)(enc->epoch_idx + 1U);
311 18 : ulong total_stake = (entry_type==2U) ? bank->f.total_epoch_stake : enc->total_stake;
312 18 : PUSH_VAL( ulong, total_stake );
313 18 : enc->state = STATE_NODE_VOTE_ACCOUNTS;
314 9 : break;
315 9 : }
316 18 : case STATE_NODE_VOTE_ACCOUNTS: {
317 18 : PUSH_VAL( ulong, 0UL ); /* node_id_to_vote_accounts_length = 0 */
318 18 : enc->state = STATE_AUTH_VOTER;
319 9 : break;
320 9 : }
321 18 : case STATE_AUTH_VOTER: {
322 18 : PUSH_VAL( ulong, 0UL ); /* epoch_authorized_voters_length = 0 */
323 9 : enc->epoch_idx++;
324 18 : enc->state = (enc->epoch_idx < enc->epoch_cnt) ? STATE_EPOCH_STAKES : STATE_LTHASH;
325 9 : break;
326 9 : }
327 6 : case STATE_LTHASH: {
328 6 : PUSH_VAL( uchar, 1 );
329 6 : PUSH_VAL( fd_lthash_value_t, bank->f.lthash );
330 6 : enc->state = STATE_BLOCK_ID;
331 3 : break;
332 3 : }
333 6 : case STATE_BLOCK_ID: {
334 3 : int has_block_id = !fd_hash_check_zero( &bank->f.block_id );
335 6 : PUSH_VAL( uchar, (uchar)has_block_id );
336 6 : if( has_block_id ) PUSH_VAL( fd_hash_t, bank->f.block_id );
337 6 : enc->state = STATE_DONE;
338 3 : break;
339 3 : }
340 6 : case STATE_DONE:
341 6 : return 0UL;
342 0 : default:
343 0 : FD_LOG_CRIT(( "invalid state reached (%u)", enc->state ));
344 210 : }
345 :
346 204 : return RET_EXPR;
347 210 : }
348 :
349 : #undef PREP
350 : #undef ENCODE_FN
351 : #undef PUSH_VAL
352 : #undef RET_EXPR
|