Line data Source code
1 : #include "fd_vote_codec_tmpl.h"
2 : #include "../../../../ballet/utf8/fd_utf8.h"
3 : #include "../../../../ballet/txn/fd_compact_u16.h"
4 : #include "../../../../ballet/txn/fd_txn.h"
5 :
6 : /**********************************************************************/
7 : /* Unified bincode (de)serialization macros. */
8 : /* All macros operate on a cursor (uchar const ** data, ulong * sz). */
9 : /* CHECK returns 1 on failure (non-zero == error). */
10 : /**********************************************************************/
11 :
12 840235 : #define CHECK( cond ) do { \
13 840235 : if( FD_UNLIKELY( !(cond) ) ) return 1; \
14 840235 : } while( 0 )
15 :
16 9734 : #define CHECK_RET_NULL( cond ) do { \
17 9734 : if( FD_UNLIKELY( !(cond) ) ) return NULL; \
18 9734 : } while( 0 )
19 :
20 4931 : #define CHECK_U64_MUL_OVERFLOW( a, b ) do { \
21 4931 : ulong _dummy; \
22 4931 : CHECK( !__builtin_umull_overflow( (a), (b), &_dummy ) ); \
23 4931 : } while( 0 )
24 :
25 : /**********************************************************************/
26 : /* Read macros */
27 : /**********************************************************************/
28 :
29 107950 : #define READ_BYTES( dst, n, data, sz ) do { \
30 107950 : CHECK( (n)<=(*(sz)) ); \
31 107950 : fd_memcpy( (dst), *(data), (n) ); \
32 107742 : *(data) += (n); \
33 107742 : *(sz) -= (n); \
34 107742 : } while( 0 )
35 :
36 6924 : #define SKIP_BYTES( n, data, sz ) do { \
37 6924 : CHECK( (n)<=(*(sz)) ); \
38 6924 : *(data) += (n); \
39 6924 : *(sz) -= (n); \
40 6924 : } while( 0 )
41 :
42 94934 : #define READ_U8( dst, data, sz ) do { \
43 94934 : CHECK( 1UL<=(*(sz)) ); \
44 94934 : (dst) = FD_LOAD( uchar, *(data) ); \
45 94907 : *(data) += 1UL; \
46 94907 : *(sz) -= 1UL; \
47 94907 : } while( 0 )
48 :
49 3144 : #define READ_U16( dst, data, sz ) do { \
50 3144 : CHECK( 2UL<=(*(sz)) ); \
51 3144 : (dst) = FD_LOAD( ushort, *(data) ); \
52 3144 : *(data) += 2UL; \
53 3144 : *(sz) -= 2UL; \
54 3144 : } while( 0 )
55 :
56 97777 : #define READ_U32( dst, data, sz ) do { \
57 97777 : CHECK( 4UL<=(*(sz)) ); \
58 97777 : (dst) = FD_LOAD( uint, *(data) ); \
59 97690 : *(data) += 4UL; \
60 97690 : *(sz) -= 4UL; \
61 97690 : } while( 0 )
62 :
63 141084 : #define READ_U64( dst, data, sz ) do { \
64 141084 : CHECK( 8UL<=(*(sz)) ); \
65 141084 : (dst) = FD_LOAD( ulong, *(data) ); \
66 141025 : *(data) += 8UL; \
67 141025 : *(sz) -= 8UL; \
68 141025 : } while( 0 )
69 :
70 1176 : #define READ_I64( dst, data, sz ) do { \
71 1176 : CHECK( 8UL<=(*(sz)) ); \
72 1176 : (dst) = FD_LOAD( long, *(data) ); \
73 1165 : *(data) += 8UL; \
74 1165 : *(sz) -= 8UL; \
75 1165 : } while( 0 )
76 :
77 : #define READ_HASH( dst, data, sz ) \
78 18116 : READ_BYTES( (dst).uc, 32UL, data, sz )
79 :
80 14234 : #define READ_PUBKEY READ_HASH
81 :
82 9318 : #define READ_BOOL( dst, data, sz ) do { \
83 9318 : READ_U8( dst, data, sz ); \
84 9318 : CHECK( (dst)==0 || (dst)==1 ); \
85 9303 : } while( 0 )
86 :
87 7884 : #define READ_OPTION READ_BOOL
88 :
89 1127 : #define READ_ENUM( dst, n, data, sz ) do { \
90 1127 : CHECK( 4UL<=(*(sz)) ); \
91 1127 : (dst) = FD_LOAD( uint, *(data) ); \
92 1125 : CHECK( (dst)<(n) ); \
93 1125 : *(data) += 4UL; \
94 1117 : *(sz) -= 4UL; \
95 1117 : } while( 0 )
96 :
97 : /* Varint decoder for u64 (LEB128). */
98 31953 : #define READ_U64_VARINT( dst, data, sz ) do { \
99 31953 : ulong _val = 0UL; \
100 31953 : uint _shift = 0U; \
101 58103 : for(;;) { \
102 58103 : CHECK( 1UL<=(*(sz)) ); \
103 58103 : uchar _byte = FD_LOAD( uchar, *(data) ); \
104 58084 : *(data) += 1UL; \
105 58084 : *(sz) -= 1UL; \
106 58084 : _val |= (ulong)(_byte & 0x7F) << _shift; \
107 58084 : if( FD_LIKELY( !(_byte & 0x80) ) ) { \
108 31943 : CHECK( (_val>>_shift)==(ulong)_byte ); /* last byte not truncated */ \
109 31943 : CHECK( _byte || !_shift ); /* no trailing zero bytes */ \
110 31943 : (dst) = _val; \
111 31936 : break; \
112 31943 : } \
113 58084 : _shift += 7U; \
114 26141 : CHECK( _shift<64U ); \
115 26141 : } \
116 31953 : } while( 0 )
117 :
118 1091 : #define READ_COMPACT_U16( dst, data, sz ) do { \
119 1091 : ulong _n = fd_cu16_dec( *(data), *(sz), &(dst) ); \
120 1091 : CHECK( _n ); \
121 1091 : *(data) += _n; \
122 1018 : *(sz) -= _n; \
123 1018 : } while( 0 )
124 :
125 : /**********************************************************************/
126 : /* Write macros */
127 : /**********************************************************************/
128 :
129 40695 : #define WRITE_BYTES( src, n, out, out_sz ) do { \
130 40695 : CHECK( (n)<=(*(out_sz)) ); \
131 40695 : fd_memcpy( *(out), (src), (n) ); \
132 40695 : *(out) += (n); \
133 40695 : *(out_sz) -= (n); \
134 40695 : } while( 0 )
135 :
136 27280 : #define WRITE_U8( val, out, out_sz ) do { \
137 27280 : CHECK( 1UL<=(*(out_sz)) ); \
138 27280 : FD_STORE( uchar, *(out), (val) ); \
139 27280 : *(out) += 1UL; \
140 27280 : *(out_sz) -= 1UL; \
141 27280 : } while( 0 )
142 :
143 2772 : #define WRITE_U16( val, out, out_sz ) do { \
144 2772 : CHECK( 2UL<=(*(out_sz)) ); \
145 2772 : FD_STORE( ushort, *(out), (val) ); \
146 2772 : *(out) += 2UL; \
147 2772 : *(out_sz) -= 2UL; \
148 2772 : } while( 0 )
149 :
150 25893 : #define WRITE_U32( val, out, out_sz ) do { \
151 25893 : CHECK( 4UL<=(*(out_sz)) ); \
152 25893 : FD_STORE( uint, *(out), (val) ); \
153 25893 : *(out) += 4UL; \
154 25893 : *(out_sz) -= 4UL; \
155 25893 : } while( 0 )
156 :
157 32682 : #define WRITE_U64( val, out, out_sz ) do { \
158 32682 : CHECK( 8UL<=(*(out_sz)) ); \
159 32682 : FD_STORE( ulong, *(out), (val) ); \
160 32682 : *(out) += 8UL; \
161 32682 : *(out_sz) -= 8UL; \
162 32682 : } while( 0 )
163 :
164 : #define WRITE_I64( val, out, out_sz ) do { \
165 : CHECK( 8UL<=(*(out_sz)) ); \
166 : FD_STORE( long, *(out), (val) ); \
167 : *(out) += 8UL; \
168 : *(out_sz) -= 8UL; \
169 : } while( 0 )
170 :
171 : #define WRITE_PUBKEY( src, out, out_sz ) \
172 7345 : WRITE_BYTES( (src).uc, 32UL, out, out_sz )
173 :
174 : #define WRITE_BOOL( val, out, out_sz ) \
175 2773 : WRITE_U8( (uchar)!!(val), out, out_sz )
176 :
177 1386 : #define WRITE_OPTION WRITE_BOOL
178 :
179 : /**********************************************************************/
180 : /* Vote account state -- deserialization helpers */
181 : /* Each returns 0 on success, 1 on failure. */
182 : /**********************************************************************/
183 :
184 : /* Votes (is_v1_14_11=1 for v1_14_11 Vec<Lockout>, 0 for v3/v4
185 : Vec<LandedVote>) */
186 : static int
187 : deser_votes( fd_landed_vote_t * votes,
188 : int is_v1_14_11,
189 : uchar const ** ptr,
190 3264 : ulong * rem ) {
191 3264 : ulong votes_len;
192 3264 : READ_U64( votes_len, ptr, rem );
193 3259 : CHECK( votes_len<=MAX_LOCKOUT_HISTORY );
194 :
195 54652 : for( ulong i=0UL; i<votes_len; i++ ) {
196 51439 : fd_landed_vote_t * elem = deq_fd_landed_vote_t_push_tail_nocopy( votes );
197 51439 : if( is_v1_14_11 ) {
198 3223 : elem->latency = 0; /* Unused field for v1_14_11 */
199 48216 : } else {
200 48216 : READ_U8( elem->latency, ptr, rem );
201 48216 : }
202 51439 : READ_U64( elem->lockout.slot, ptr, rem );
203 51439 : READ_U32( elem->lockout.confirmation_count, ptr, rem );
204 51439 : }
205 3213 : return 0;
206 3213 : }
207 :
208 : /* Root slot (Option<u64>) */
209 : static int
210 : deser_root_slot( uchar * has_root_slot,
211 : ulong * root_slot,
212 : uchar const ** ptr,
213 3215 : ulong * rem ) {
214 3215 : uchar opt;
215 3215 : READ_OPTION( opt, ptr, rem );
216 3203 : *has_root_slot = opt;
217 3203 : if( opt ) {
218 1678 : READ_U64( *root_slot, ptr, rem );
219 1678 : }
220 3198 : return 0;
221 3203 : }
222 :
223 : /* Authorized voters (BTreeMap<u64, Pubkey>) */
224 : static int
225 : deser_authorized_voters( fd_vote_authorized_voter_t * pool,
226 : fd_vote_authorized_voters_treap_t * treap,
227 : uchar const ** ptr,
228 3198 : ulong * rem ) {
229 3198 : ulong authorized_voters_len;
230 3198 : READ_U64( authorized_voters_len, ptr, rem );
231 3192 : CHECK( authorized_voters_len<=MAX_AUTHORIZED_VOTERS );
232 6537 : for( ulong i=0UL; i<authorized_voters_len; i++ ) {
233 3482 : fd_vote_authorized_voter_t * voter = fd_vote_authorized_voters_pool_ele_acquire( pool );
234 3482 : READ_U64( voter->epoch, ptr, rem );
235 3482 : READ_PUBKEY( voter->pubkey, ptr, rem );
236 3482 : voter->prio = voter->pubkey.uc[0];
237 :
238 : /* Check for existing entries, overwrite if exists */
239 3482 : fd_vote_authorized_voter_t * existing_voter = fd_vote_authorized_voters_treap_ele_query( treap, voter->epoch, pool );
240 3482 : if( FD_UNLIKELY( existing_voter ) ) {
241 2 : fd_vote_authorized_voters_treap_ele_remove( treap, existing_voter, pool );
242 2 : fd_vote_authorized_voters_pool_ele_release( pool, existing_voter );
243 2 : }
244 :
245 3482 : fd_vote_authorized_voters_treap_ele_insert( treap, voter, pool );
246 3482 : }
247 3055 : return 0;
248 3055 : }
249 :
250 : /* Prior voters (fixed-size circular buffer of 32 entries)
251 : We can directly memcpy the entire buffer because the wire
252 : format is identical to the in-memory representation of the
253 : array. */
254 : static int
255 : deser_prior_voters( fd_vote_prior_voters_t * prior_voters,
256 : uchar const ** ptr,
257 1483 : ulong * rem ) {
258 1483 : READ_BYTES( prior_voters->buf, PRIOR_VOTERS_MAX*sizeof(fd_vote_prior_voter_t), ptr, rem );
259 1434 : READ_U64( prior_voters->idx, ptr, rem );
260 1434 : READ_BOOL( prior_voters->is_empty, ptr, rem );
261 1429 : return 0;
262 1434 : }
263 :
264 : /* Epoch credits (Vec<EpochCredits>) */
265 : static int
266 : deser_epoch_credits( fd_vote_epoch_credits_t * epoch_credits,
267 : uchar const ** ptr,
268 3002 : ulong * rem ) {
269 3002 : ulong epoch_credits_len;
270 3002 : READ_U64( epoch_credits_len, ptr, rem );
271 3000 : CHECK( epoch_credits_len<=MAX_EPOCH_CREDITS_HISTORY );
272 86877 : for( ulong i=0UL; i<epoch_credits_len; i++ ) {
273 83883 : fd_vote_epoch_credits_t * elem = deq_fd_vote_epoch_credits_t_push_tail_nocopy( epoch_credits );
274 83883 : READ_BYTES( elem, sizeof(fd_vote_epoch_credits_t), ptr, rem );
275 83883 : }
276 2994 : return 0;
277 2996 : }
278 :
279 : /**********************************************************************/
280 : /* Vote account state -- serialization helpers */
281 : /* Each returns 0 on success, 1 on failure. */
282 : /**********************************************************************/
283 :
284 : /* Votes (is_v1_14_11=1 for v1_14_11 Vec<Lockout>, 0 for v3/v4
285 : Vec<LandedVote>) */
286 : static int
287 : ser_votes( fd_landed_vote_t const * votes,
288 : int is_v1_14_11,
289 : uchar ** out,
290 1387 : ulong * out_sz ) {
291 1387 : if( FD_UNLIKELY( votes==NULL ) ) {
292 0 : WRITE_U64( 0UL, out, out_sz );
293 0 : return 0;
294 0 : }
295 :
296 1387 : ulong votes_len = deq_fd_landed_vote_t_cnt( votes );
297 1387 : WRITE_U64( votes_len, out, out_sz );
298 :
299 1387 : for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( votes );
300 25894 : !deq_fd_landed_vote_t_iter_done( votes, iter );
301 24507 : iter = deq_fd_landed_vote_t_iter_next( votes, iter ) ) {
302 24507 : fd_landed_vote_t const * elem = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
303 24507 : if( !is_v1_14_11 ) {
304 24507 : WRITE_U8( elem->latency, out, out_sz );
305 24507 : }
306 24507 : WRITE_U64( elem->lockout.slot, out, out_sz );
307 24507 : WRITE_U32( elem->lockout.confirmation_count, out, out_sz );
308 24507 : }
309 1387 : return 0;
310 1387 : }
311 :
312 : /* Root slot (Option<u64>) */
313 : static int
314 : ser_root_slot( uchar has_root_slot,
315 : ulong root_slot,
316 : uchar ** out,
317 1387 : ulong * out_sz ) {
318 1387 : WRITE_BOOL( has_root_slot, out, out_sz );
319 1387 : if( has_root_slot ) {
320 827 : WRITE_U64( root_slot, out, out_sz );
321 827 : }
322 1387 : return 0;
323 1387 : }
324 :
325 : /* Authorized voters (BTreeMap<u64, Pubkey>) */
326 : static int
327 : ser_authorized_voters( fd_vote_authorized_voter_t const * pool,
328 : fd_vote_authorized_voters_treap_t const * treap,
329 : uchar ** out,
330 1387 : ulong * out_sz ) {
331 1387 : if( FD_UNLIKELY( treap==NULL ) ) {
332 0 : WRITE_U64( 0UL, out, out_sz );
333 0 : return 0;
334 0 : }
335 :
336 1387 : ulong len = fd_vote_authorized_voters_treap_ele_cnt( treap );
337 1387 : WRITE_U64( len, out, out_sz );
338 :
339 1387 : for( fd_vote_authorized_voters_treap_fwd_iter_t iter = fd_vote_authorized_voters_treap_fwd_iter_init( treap, pool );
340 3188 : !fd_vote_authorized_voters_treap_fwd_iter_done( iter );
341 1801 : iter = fd_vote_authorized_voters_treap_fwd_iter_next( iter, pool ) ) {
342 1801 : fd_vote_authorized_voter_t const * voter = fd_vote_authorized_voters_treap_fwd_iter_ele_const( iter, pool );
343 1801 : WRITE_U64( voter->epoch, out, out_sz );
344 1801 : WRITE_PUBKEY( voter->pubkey, out, out_sz );
345 1801 : }
346 1387 : return 0;
347 1387 : }
348 :
349 : /* Prior voters (fixed-size circular buffer of 32 entries)
350 : We can directly memcpy the entire buffer because the wire
351 : format is identical to the in-memory representation of the
352 : array. */
353 : static int
354 : ser_prior_voters( fd_vote_prior_voters_t const * prior_voters,
355 : uchar ** out,
356 0 : ulong * out_sz ) {
357 0 : WRITE_BYTES( prior_voters->buf, PRIOR_VOTERS_MAX*sizeof(fd_vote_prior_voter_t), out, out_sz );
358 0 : WRITE_U64( prior_voters->idx, out, out_sz );
359 0 : WRITE_BOOL( prior_voters->is_empty, out, out_sz );
360 0 : return 0;
361 0 : }
362 :
363 : /* Epoch credits (Vec<EpochCredits>) */
364 : static int
365 : ser_epoch_credits( fd_vote_epoch_credits_t const * epoch_credits,
366 : uchar ** out,
367 1387 : ulong * out_sz ) {
368 1387 : if( FD_UNLIKELY( epoch_credits==NULL ) ) {
369 0 : WRITE_U64( 0UL, out, out_sz );
370 0 : return 0;
371 0 : }
372 :
373 1387 : ulong len = deq_fd_vote_epoch_credits_t_cnt( epoch_credits );
374 1387 : WRITE_U64( len, out, out_sz );
375 :
376 1387 : for( deq_fd_vote_epoch_credits_t_iter_t iter = deq_fd_vote_epoch_credits_t_iter_init( epoch_credits );
377 33246 : !deq_fd_vote_epoch_credits_t_iter_done( epoch_credits, iter );
378 31859 : iter = deq_fd_vote_epoch_credits_t_iter_next( epoch_credits, iter ) ) {
379 31859 : fd_vote_epoch_credits_t const * elem = deq_fd_vote_epoch_credits_t_iter_ele_const( epoch_credits, iter );
380 31859 : WRITE_BYTES( elem, sizeof(fd_vote_epoch_credits_t), out, out_sz );
381 31859 : }
382 1387 : return 0;
383 1387 : }
384 :
385 : /**********************************************************************/
386 : /* Wire layout offsets */
387 : /**********************************************************************/
388 :
389 : /* Fixed-offset byte positions within the bincode wire format.
390 : For v1_14_11 and v3 the fixed prefix is: discriminant, node_pubkey,
391 : authorized_withdrawer, commission. For v4 the prefix additionally
392 : includes inflation_rewards_collector, block_revenue_collector,
393 : inflation_rewards_commission_bps, block_revenue_commission_bps,
394 : and pending_delegator_rewards before the first variable field. */
395 :
396 104 : #define WIRE_OFF_NODE_PUBKEY (4UL)
397 0 : #define WIRE_OFF_V1V3_COMMISSION (68UL) /* 4 + 32 + 32 */
398 104 : #define WIRE_OFF_V4_INFLATION_REWARDS_COLLECTOR (68UL) /* 4 + 32 + 32 */
399 104 : #define WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR (100UL) /* 4 + 32 + 32 + 32 */
400 : #define WIRE_OFF_V4_COMMISSION_BPS (132UL) /* 4 + 32 + 32 + 32 + 32 */
401 : #define WIRE_OFF_V4_BLOCK_REVENUE_COMMISSION_BPS (134UL) /* 4 + 32 + 32 + 32 + 32 + 2 */
402 : #define WIRE_OFF_V4_PENDING_DELEGATOR_REWARDS (136UL) /* 4 + 32 + 32 + 32 + 32 + 2 + 2 */
403 :
404 : /* Byte size of a Lockout on the wire: u64 slot + u32 confirmation_count */
405 0 : #define WIRE_LOCKOUT_SZ (12UL)
406 : /* Byte size of a LandedVote on the wire: u8 latency + u64 slot + u32 confirmation_count */
407 1386 : #define WIRE_LANDED_VOTE_SZ (13UL)
408 : /* Byte size of an authorized voter entry: u64 epoch + 32B pubkey */
409 1386 : #define WIRE_AUTH_VOTER_SZ (40UL)
410 : /* Byte size of prior_voters on the wire: 32 * 48B + 8B idx + 1B is_empty */
411 0 : #define WIRE_PRIOR_VOTERS_SZ (PRIOR_VOTERS_MAX * 48UL + 8UL + 1UL)
412 :
413 : /* Offset of the votes vector (v1/v3) or BLS option (v4) — first byte
414 : after the fixed-offset prefix. */
415 0 : #define WIRE_VOTES_OFF_V1_V3 (69UL) /* 4 + 32 + 32 + 1 */
416 1805 : #define WIRE_BLS_OFF_V4 (144UL) /* 4 + 32 + 32 + 32 + 32 + 2 + 2 + 8 */
417 :
418 : /**********************************************************************/
419 : /* Vote account state -- direct field accessors */
420 : /* These read fields directly from raw bincode-encoded vote account */
421 : /* data without full deserialization. */
422 : /**********************************************************************/
423 :
424 : int
425 : fd_vote_account_node_pubkey( uchar const * data,
426 : ulong data_sz,
427 104 : fd_pubkey_t * out ) {
428 104 : CHECK( data_sz>=WIRE_OFF_NODE_PUBKEY+32UL );
429 104 : fd_memcpy( out, data+WIRE_OFF_NODE_PUBKEY, 32UL );
430 104 : return 0;
431 104 : }
432 :
433 : int
434 : fd_vote_account_commission_bps( uchar const * data,
435 : ulong data_sz,
436 : int commission_rate_in_basis_points,
437 104 : ushort * out ) {
438 104 : uchar const * ptr = data;
439 104 : ulong remaining = data_sz;
440 :
441 104 : uint discriminant;
442 104 : READ_U32( discriminant, &ptr, &remaining );
443 :
444 104 : switch( discriminant ) {
445 0 : case fd_vote_state_versioned_enum_v1_14_11: /* fallthrough */
446 0 : case fd_vote_state_versioned_enum_v3:
447 0 : CHECK( data_sz>WIRE_OFF_V1V3_COMMISSION );
448 0 : *out = data[ WIRE_OFF_V1V3_COMMISSION ] * 100U;
449 0 : return 0;
450 104 : case fd_vote_state_versioned_enum_v4:
451 104 : CHECK( data_sz>=WIRE_OFF_V4_COMMISSION_BPS+2UL );
452 104 : *out = FD_LOAD( ushort, data+WIRE_OFF_V4_COMMISSION_BPS );
453 :
454 : /* Round down to the nearest whole percentage if SIMD-0291 is not
455 : yet active. */
456 104 : if( !commission_rate_in_basis_points ) {
457 0 : *out = (*out / 100U) * 100U;
458 0 : }
459 104 : return 0;
460 0 : default:
461 0 : return 1;
462 104 : }
463 104 : }
464 :
465 : int
466 : fd_vote_account_block_revenue_commission_bps( uchar const * data,
467 : ulong data_sz,
468 104 : ushort * out ) {
469 104 : uchar const * ptr = data;
470 104 : ulong remaining = data_sz;
471 :
472 104 : uint discriminant;
473 104 : READ_U32( discriminant, &ptr, &remaining );
474 :
475 104 : switch( discriminant ) {
476 0 : case fd_vote_state_versioned_enum_v1_14_11: /* fallthrough */
477 0 : case fd_vote_state_versioned_enum_v3:
478 0 : *out = FD_VOTE_DEFAULT_BLOCK_REVENUE_COMMISSION_BPS;
479 0 : return 0;
480 104 : case fd_vote_state_versioned_enum_v4:
481 104 : CHECK( data_sz>=WIRE_OFF_V4_BLOCK_REVENUE_COMMISSION_BPS+2UL );
482 104 : *out = FD_LOAD( ushort, data+WIRE_OFF_V4_BLOCK_REVENUE_COMMISSION_BPS );
483 104 : return 0;
484 0 : default:
485 0 : return 1;
486 104 : }
487 104 : }
488 :
489 : int
490 : fd_vote_account_pending_delegator_rewards( uchar const * data,
491 : ulong data_sz,
492 209 : ulong * out ) {
493 209 : uchar const * ptr = data;
494 209 : ulong remaining = data_sz;
495 :
496 209 : uint discriminant;
497 209 : READ_U32( discriminant, &ptr, &remaining );
498 :
499 209 : switch( discriminant ) {
500 0 : case fd_vote_state_versioned_enum_v1_14_11: /* fallthrough */
501 4 : case fd_vote_state_versioned_enum_v3:
502 4 : *out = 0UL;
503 4 : return 0;
504 205 : case fd_vote_state_versioned_enum_v4:
505 205 : CHECK( data_sz==FD_VOTE_STATE_V4_SZ );
506 205 : *out = FD_LOAD( ulong, data+WIRE_OFF_V4_PENDING_DELEGATOR_REWARDS );
507 205 : return 0;
508 0 : default:
509 0 : return 1;
510 209 : }
511 209 : }
512 :
513 : /* Returns 1 iff data is an initialized v4 vote state of exactly
514 : FD_VOTE_STATE_V4_SZ bytes. */
515 : static int
516 : is_v4_with_pending_delegator_rewards( uchar const * data,
517 61 : ulong data_sz ) {
518 61 : if( data_sz!=FD_VOTE_STATE_V4_SZ ) return 0;
519 61 : return FD_LOAD( uint, data )==fd_vote_state_versioned_enum_v4;
520 61 : }
521 :
522 : int
523 : fd_vote_account_add_pending_delegator_rewards( uchar * data,
524 : ulong data_sz,
525 4 : ulong lamports ) {
526 4 : if( FD_UNLIKELY( !is_v4_with_pending_delegator_rewards( data, data_sz ) ) ) return 1;
527 4 : ulong cur = FD_LOAD( ulong, data+WIRE_OFF_V4_PENDING_DELEGATOR_REWARDS );
528 4 : ulong sum;
529 4 : if( FD_UNLIKELY( __builtin_uaddl_overflow( cur, lamports, &sum ) ) ) return 2;
530 4 : FD_STORE( ulong, data+WIRE_OFF_V4_PENDING_DELEGATOR_REWARDS, sum );
531 4 : return 0;
532 4 : }
533 :
534 : int
535 : fd_vote_account_reset_pending_delegator_rewards( uchar * data,
536 : ulong data_sz,
537 57 : ulong * old_out ) {
538 57 : if( FD_UNLIKELY( !is_v4_with_pending_delegator_rewards( data, data_sz ) ) ) return 1;
539 57 : *old_out = FD_LOAD( ulong, data+WIRE_OFF_V4_PENDING_DELEGATOR_REWARDS );
540 57 : FD_STORE( ulong, data+WIRE_OFF_V4_PENDING_DELEGATOR_REWARDS, 0UL );
541 57 : return 0;
542 57 : }
543 :
544 : int
545 : fd_vote_account_collectors( uchar const * data,
546 : ulong data_sz,
547 : fd_pubkey_t const * vote_pubkey,
548 : fd_pubkey_t const * node_pubkey,
549 : fd_pubkey_t * inflation_rewards_collector_out,
550 104 : fd_pubkey_t * block_revenue_collector_out ) {
551 104 : uchar const * ptr = data;
552 104 : ulong remaining = data_sz;
553 :
554 104 : uint discriminant;
555 104 : READ_U32( discriminant, &ptr, &remaining );
556 :
557 104 : switch( discriminant ) {
558 0 : case fd_vote_state_versioned_enum_v1_14_11: /* fallthrough */
559 0 : case fd_vote_state_versioned_enum_v3:
560 : /* Pre-v4 vote states have no collector fields: default to the
561 : vote account (inflation) and the node identity (block
562 : revenue). */
563 0 : *inflation_rewards_collector_out = *vote_pubkey;
564 0 : *block_revenue_collector_out = *node_pubkey;
565 0 : return 0;
566 104 : case fd_vote_state_versioned_enum_v4:
567 104 : CHECK( data_sz>=WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR+32UL );
568 104 : fd_memcpy( inflation_rewards_collector_out, data+WIRE_OFF_V4_INFLATION_REWARDS_COLLECTOR, 32UL );
569 104 : fd_memcpy( block_revenue_collector_out, data+WIRE_OFF_V4_BLOCK_REVENUE_COLLECTOR, 32UL );
570 104 : return 0;
571 0 : default:
572 0 : return 1;
573 104 : }
574 104 : }
575 :
576 : /* Seeks past variable-length fields to the start of epoch_credits.
577 : On success sets *out_ptr to the first entry and *out_cnt to the
578 : entry count. Returns 0 on success, 1 on error. */
579 :
580 : /* seek_authorized_voters positions *out_ptr at the first entry of the
581 : authorized_voters map (sorted by ascending epoch, WIRE_AUTH_VOTER_SZ
582 : bytes each) and stores the entry count in *out_cnt. All entries
583 : are bounds checked. Returns 0 on success, 1 on malformed data. */
584 :
585 : static int
586 : seek_authorized_voters( uchar const * data,
587 : ulong data_sz,
588 : uint * out_discriminant,
589 : uchar const ** out_ptr,
590 : ulong * out_remaining,
591 1645 : ulong * out_cnt ) {
592 1645 : uchar const * ptr = data;
593 1645 : ulong remaining = data_sz;
594 :
595 1645 : uint discriminant;
596 1645 : READ_U32( discriminant, &ptr, &remaining );
597 :
598 1645 : switch( discriminant ) {
599 0 : case fd_vote_state_versioned_enum_v1_14_11: {
600 0 : SKIP_BYTES( WIRE_VOTES_OFF_V1_V3-4UL, &ptr, &remaining );
601 :
602 : /* Skip votes Vec<Lockout> */
603 0 : ulong votes_len;
604 0 : READ_U64( votes_len, &ptr, &remaining );
605 0 : CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LOCKOUT_SZ );
606 0 : SKIP_BYTES( votes_len*WIRE_LOCKOUT_SZ, &ptr, &remaining );
607 0 : break;
608 0 : }
609 :
610 6 : case fd_vote_state_versioned_enum_v3: {
611 6 : SKIP_BYTES( WIRE_VOTES_OFF_V1_V3-4UL, &ptr, &remaining );
612 :
613 : /* Skip votes Vec<LandedVote> */
614 6 : ulong votes_len;
615 6 : READ_U64( votes_len, &ptr, &remaining );
616 6 : CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LANDED_VOTE_SZ );
617 6 : SKIP_BYTES( votes_len*WIRE_LANDED_VOTE_SZ, &ptr, &remaining );
618 6 : break;
619 6 : }
620 :
621 1637 : case fd_vote_state_versioned_enum_v4: {
622 1637 : SKIP_BYTES( WIRE_BLS_OFF_V4-4UL, &ptr, &remaining );
623 :
624 : /* Skip Option<bls_pubkey_compressed> */
625 1637 : uchar has_bls_pubkey;
626 1637 : READ_U8( has_bls_pubkey, &ptr, &remaining );
627 1637 : if( has_bls_pubkey ) {
628 1031 : SKIP_BYTES( FD_BLS_PUBKEY_COMPRESSED_SZ, &ptr, &remaining );
629 1031 : }
630 :
631 : /* Skip votes Vec<LandedVote> */
632 1637 : ulong votes_len;
633 1637 : READ_U64( votes_len, &ptr, &remaining );
634 1637 : CHECK_U64_MUL_OVERFLOW( votes_len, WIRE_LANDED_VOTE_SZ );
635 1637 : SKIP_BYTES( votes_len*WIRE_LANDED_VOTE_SZ, &ptr, &remaining );
636 1637 : break;
637 1637 : }
638 :
639 1637 : default:
640 0 : return 1;
641 1645 : }
642 :
643 : /* Skip root_slot Option<u64> */
644 1643 : uchar has_root_slot;
645 1643 : READ_U8( has_root_slot, &ptr, &remaining );
646 1643 : if( has_root_slot ) {
647 956 : SKIP_BYTES( 8UL, &ptr, &remaining );
648 956 : }
649 :
650 : /* Now at authorized_voters BTreeMap<u64, Pubkey> */
651 1643 : ulong authorized_voters_len;
652 1643 : READ_U64( authorized_voters_len, &ptr, &remaining );
653 1643 : CHECK_U64_MUL_OVERFLOW( authorized_voters_len, WIRE_AUTH_VOTER_SZ );
654 1643 : CHECK( authorized_voters_len*WIRE_AUTH_VOTER_SZ<=remaining );
655 :
656 1643 : *out_discriminant = discriminant;
657 1643 : *out_ptr = ptr;
658 1643 : *out_remaining = remaining;
659 1643 : *out_cnt = authorized_voters_len;
660 1643 : return 0;
661 1643 : }
662 :
663 : static int
664 : seek_epoch_credits( uchar const * data,
665 : ulong data_sz,
666 : fd_vote_epoch_credits_t const ** out_ptr,
667 1645 : ulong * out_cnt ) {
668 1645 : uint discriminant;
669 1645 : uchar const * ptr;
670 1645 : ulong remaining;
671 1645 : ulong authorized_voters_len;
672 1645 : CHECK( !seek_authorized_voters( data, data_sz, &discriminant, &ptr, &remaining, &authorized_voters_len ) );
673 1645 : SKIP_BYTES( authorized_voters_len*WIRE_AUTH_VOTER_SZ, &ptr, &remaining );
674 :
675 : /* Skip prior_voters (fixed size), absent in v4 */
676 1645 : if( discriminant!=fd_vote_state_versioned_enum_v4 ) {
677 6 : SKIP_BYTES( WIRE_PRIOR_VOTERS_SZ, &ptr, &remaining );
678 6 : }
679 :
680 : /* Now at epoch_credits deque */
681 1645 : ulong epoch_credits_len;
682 1645 : READ_U64( epoch_credits_len, &ptr, &remaining );
683 1645 : CHECK( epoch_credits_len<=MAX_EPOCH_CREDITS_HISTORY );
684 1645 : CHECK_U64_MUL_OVERFLOW( epoch_credits_len, sizeof(fd_vote_epoch_credits_t) );
685 1645 : CHECK( epoch_credits_len*sizeof(fd_vote_epoch_credits_t)<=remaining );
686 :
687 1645 : *out_ptr = (fd_vote_epoch_credits_t const *)ptr;
688 1645 : *out_cnt = epoch_credits_len;
689 1645 : return 0;
690 1645 : }
691 :
692 : int
693 : fd_vote_account_authorized_voter( uchar const * data,
694 : ulong data_sz,
695 : ulong epoch,
696 0 : fd_pubkey_t * out ) {
697 0 : uint discriminant;
698 0 : uchar const * ptr;
699 0 : ulong remaining;
700 0 : ulong cnt;
701 0 : CHECK( !seek_authorized_voters( data, data_sz, &discriminant, &ptr, &remaining, &cnt ) );
702 :
703 : /* Take the last entry whose epoch is at or before the requested one. */
704 0 : int found = 0;
705 0 : for( ulong i=0UL; i<cnt; i++, ptr+=WIRE_AUTH_VOTER_SZ ) {
706 0 : if( FD_LOAD( ulong, ptr )>epoch ) continue;
707 0 : fd_memcpy( out, ptr+8UL, 32UL );
708 0 : found = 1;
709 0 : }
710 :
711 0 : return !found;
712 0 : }
713 :
714 : int
715 : fd_vote_account_last_timestamp( uchar const * data,
716 : ulong data_sz,
717 1540 : fd_vote_block_timestamp_t * out ) {
718 1540 : fd_vote_epoch_credits_t const * epoch_credits_ptr;
719 1540 : ulong epoch_credits_len;
720 1540 : CHECK( !seek_epoch_credits( data, data_sz, &epoch_credits_ptr, &epoch_credits_len ) );
721 :
722 1540 : uchar const * timestamp_ptr = (uchar const *)( epoch_credits_ptr + epoch_credits_len );
723 1540 : CHECK( timestamp_ptr+sizeof(fd_vote_block_timestamp_t)<=data+data_sz );
724 :
725 1540 : fd_memcpy( out, timestamp_ptr, sizeof(fd_vote_block_timestamp_t) );
726 1540 : return 0;
727 1540 : }
728 :
729 : int
730 : fd_vote_account_is_v4_with_bls_pubkey( uchar const * data,
731 317 : ulong data_sz ) {
732 317 : if( FD_UNLIKELY( data_sz<WIRE_BLS_OFF_V4+1UL ) ) return 0;
733 317 : uint discriminant = FD_LOAD( uint, data );
734 317 : if( discriminant!=fd_vote_state_versioned_enum_v4 ) return 0;
735 315 : return !!data[ WIRE_BLS_OFF_V4 ];
736 317 : }
737 :
738 : int
739 : fd_vote_account_bls_pubkey( uchar const * data,
740 : ulong data_sz,
741 104 : uchar out[ static FD_BLS_PUBKEY_COMPRESSED_SZ ] ) {
742 104 : if( FD_UNLIKELY( !fd_vote_account_is_v4_with_bls_pubkey( data, data_sz ) ) ) return 1;
743 104 : if( FD_UNLIKELY( data_sz<WIRE_BLS_OFF_V4+1UL+FD_BLS_PUBKEY_COMPRESSED_SZ ) ) return 1;
744 104 : fd_memcpy( out, data+WIRE_BLS_OFF_V4+1UL, FD_BLS_PUBKEY_COMPRESSED_SZ );
745 104 : return 0;
746 104 : }
747 :
748 : fd_vote_epoch_credits_t const *
749 : fd_vote_account_epoch_credits( uchar const * data,
750 : ulong data_sz,
751 104 : ulong * cnt ) {
752 104 : fd_vote_epoch_credits_t const * ptr;
753 104 : CHECK_RET_NULL( !seek_epoch_credits( data, data_sz, &ptr, cnt ) );
754 104 : return ptr;
755 104 : }
756 :
757 : /**********************************************************************/
758 : /* Vote account state -- public API */
759 : /**********************************************************************/
760 :
761 : fd_vote_state_versioned_t *
762 : fd_vote_state_versioned_new( fd_vote_state_versioned_t * self,
763 4477 : uint kind ) {
764 4477 : if( FD_UNLIKELY( !self ) ) {
765 0 : FD_LOG_WARNING(( "NULL mem" ));
766 0 : return NULL;
767 0 : }
768 :
769 : /* Init and join data structures */
770 4477 : fd_landed_vote_t * votes = deq_fd_landed_vote_t_join(
771 4477 : deq_fd_landed_vote_t_new( self->landed_votes_mem, MAX_LOCKOUT_HISTORY_CAPACITY )
772 4477 : );
773 4477 : fd_vote_epoch_credits_t * epoch_credits = deq_fd_vote_epoch_credits_t_join(
774 4477 : deq_fd_vote_epoch_credits_t_new( self->epoch_credits_mem )
775 4477 : );
776 4477 : fd_vote_authorized_voter_t * authorized_voters_pool = fd_vote_authorized_voters_pool_join(
777 4477 : fd_vote_authorized_voters_pool_new( self->authorized_voters_pool_mem, MAX_AUTHORIZED_VOTERS_CAPACITY )
778 4477 : );
779 4477 : fd_vote_authorized_voters_treap_t * authorized_voters_treap = fd_vote_authorized_voters_treap_join(
780 4477 : fd_vote_authorized_voters_treap_new( self->authorized_voters_treap_mem, MAX_AUTHORIZED_VOTERS_CAPACITY )
781 4477 : );
782 :
783 4477 : self->kind = kind;
784 4477 : switch( kind ) {
785 825 : case fd_vote_state_versioned_enum_uninitialized:
786 825 : break;
787 281 : case fd_vote_state_versioned_enum_v1_14_11:
788 281 : memset( &self->v1_14_11, 0, sizeof(fd_vote_state_1_14_11_t) );
789 281 : self->v1_14_11.votes = votes;
790 281 : self->v1_14_11.epoch_credits = epoch_credits;
791 281 : self->v1_14_11.authorized_voters.pool = authorized_voters_pool;
792 281 : self->v1_14_11.authorized_voters.treap = authorized_voters_treap;
793 281 : break;
794 1440 : case fd_vote_state_versioned_enum_v3:
795 1440 : memset( &self->v3, 0, sizeof(fd_vote_state_v3_t) );
796 1440 : self->v3.votes = votes;
797 1440 : self->v3.epoch_credits = epoch_credits;
798 1440 : self->v3.authorized_voters.pool = authorized_voters_pool;
799 1440 : self->v3.authorized_voters.treap = authorized_voters_treap;
800 1440 : break;
801 1738 : case fd_vote_state_versioned_enum_v4:
802 1738 : memset( &self->v4, 0, sizeof(fd_vote_state_v4_t) );
803 1738 : self->v4.votes = votes;
804 1738 : self->v4.epoch_credits = epoch_credits;
805 1738 : self->v4.authorized_voters.pool = authorized_voters_pool;
806 1738 : self->v4.authorized_voters.treap = authorized_voters_treap;
807 1738 : break;
808 193 : default:
809 193 : return NULL;
810 4477 : }
811 :
812 4281 : return self;
813 4477 : }
814 :
815 : static int
816 : fd_vote_state_versioned_deserialize_inner( fd_vote_state_versioned_t * self,
817 : uchar const * payload,
818 4337 : ulong payload_sz ) {
819 4337 : CHECK( self!=NULL );
820 4337 : CHECK( payload!=NULL );
821 :
822 4337 : uchar const * ptr = payload;
823 4337 : ulong rem = payload_sz;
824 :
825 4337 : uint kind;
826 4337 : READ_U32( kind, &ptr, &rem );
827 :
828 4312 : CHECK( fd_vote_state_versioned_new( self, kind )!=NULL );
829 :
830 4119 : switch( self->kind ) {
831 825 : case fd_vote_state_versioned_enum_uninitialized:
832 : /* No-op, nothing to decode */
833 825 : return 0;
834 :
835 281 : case fd_vote_state_versioned_enum_v1_14_11: {
836 281 : READ_PUBKEY( self->v1_14_11.node_pubkey, &ptr, &rem );
837 278 : READ_PUBKEY( self->v1_14_11.authorized_withdrawer, &ptr, &rem );
838 272 : READ_U8( self->v1_14_11.commission, &ptr, &rem );
839 270 : CHECK( !deser_votes( self->v1_14_11.votes, 1, &ptr, &rem ) ); /* v1_14_11 wire format is Lockout, not LandedVote */
840 248 : CHECK( !deser_root_slot( &self->v1_14_11.has_root_slot, &self->v1_14_11.root_slot, &ptr, &rem ) );
841 239 : CHECK( !deser_authorized_voters( self->v1_14_11.authorized_voters.pool, self->v1_14_11.authorized_voters.treap, &ptr, &rem ) );
842 179 : CHECK( !deser_prior_voters( &self->v1_14_11.prior_voters, &ptr, &rem ) );
843 150 : CHECK( !deser_epoch_credits( self->v1_14_11.epoch_credits, &ptr, &rem ) );
844 147 : READ_BYTES( &self->v1_14_11.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
845 145 : break;
846 147 : }
847 :
848 1442 : case fd_vote_state_versioned_enum_v3: {
849 1442 : READ_PUBKEY( self->v3.node_pubkey, &ptr, &rem );
850 1431 : READ_PUBKEY( self->v3.authorized_withdrawer, &ptr, &rem );
851 1427 : READ_U8( self->v3.commission, &ptr, &rem );
852 1424 : CHECK( !deser_votes( self->v3.votes, 0, &ptr, &rem ) );
853 1395 : CHECK( !deser_root_slot( &self->v3.has_root_slot, &self->v3.root_slot, &ptr, &rem ) );
854 1387 : CHECK( !deser_authorized_voters( self->v3.authorized_voters.pool, self->v3.authorized_voters.treap, &ptr, &rem ) );
855 1304 : CHECK( !deser_prior_voters( &self->v3.prior_voters, &ptr, &rem ) );
856 1279 : CHECK( !deser_epoch_credits( self->v3.epoch_credits, &ptr, &rem ) );
857 1274 : READ_BYTES( &self->v3.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
858 1270 : break;
859 1274 : }
860 :
861 1573 : case fd_vote_state_versioned_enum_v4: {
862 1573 : READ_PUBKEY( self->v4.node_pubkey, &ptr, &rem );
863 1571 : READ_PUBKEY( self->v4.authorized_withdrawer, &ptr, &rem );
864 1571 : READ_PUBKEY( self->v4.inflation_rewards_collector, &ptr, &rem );
865 1571 : READ_PUBKEY( self->v4.block_revenue_collector, &ptr, &rem );
866 1571 : READ_U16( self->v4.inflation_rewards_commission_bps, &ptr, &rem );
867 1571 : READ_U16( self->v4.block_revenue_commission_bps, &ptr, &rem );
868 1571 : READ_U64( self->v4.pending_delegator_rewards, &ptr, &rem );
869 :
870 : /* Option<[u8; 48]> */
871 1571 : READ_OPTION( self->v4.has_bls_pubkey_compressed, &ptr, &rem );
872 1571 : if( self->v4.has_bls_pubkey_compressed ) {
873 365 : READ_BYTES( self->v4.bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ, &ptr, &rem );
874 365 : }
875 :
876 1571 : CHECK( !deser_votes( self->v4.votes, 0, &ptr, &rem ) );
877 1571 : CHECK( !deser_root_slot( &self->v4.has_root_slot, &self->v4.root_slot, &ptr, &rem ) );
878 1571 : CHECK( !deser_authorized_voters( self->v4.authorized_voters.pool, self->v4.authorized_voters.treap, &ptr, &rem ) );
879 1571 : CHECK( !deser_epoch_credits( self->v4.epoch_credits, &ptr, &rem ) ); /* v4 has no prior_voters */
880 1571 : READ_BYTES( &self->v4.last_timestamp, sizeof(fd_vote_block_timestamp_t), &ptr, &rem );
881 1571 : break;
882 1571 : }
883 :
884 1571 : default:
885 0 : return 1;
886 4119 : }
887 :
888 2988 : return 0;
889 4119 : }
890 :
891 : fd_vote_state_versioned_t *
892 : fd_vote_state_versioned_deserialize( fd_vote_state_versioned_t * self,
893 : uchar const * payload,
894 4337 : ulong payload_sz ) {
895 4337 : CHECK_RET_NULL( !fd_vote_state_versioned_deserialize_inner( self, payload, payload_sz ) );
896 3809 : return self;
897 4337 : }
898 :
899 : int
900 : fd_vote_state_versioned_serialize( fd_vote_state_versioned_t const * self,
901 : uchar * buf,
902 1386 : ulong buf_sz ) {
903 1386 : CHECK( self!=NULL );
904 1386 : CHECK( buf!=NULL );
905 :
906 1386 : uchar * out = buf;
907 1386 : ulong out_sz = buf_sz;
908 :
909 1386 : WRITE_U32( self->kind, &out, &out_sz );
910 :
911 1386 : switch( self->kind ) {
912 0 : case fd_vote_state_versioned_enum_uninitialized:
913 : /* No-op, nothing to encode */
914 0 : return 0;
915 :
916 0 : case fd_vote_state_versioned_enum_v1_14_11: {
917 0 : WRITE_PUBKEY( self->v1_14_11.node_pubkey, &out, &out_sz );
918 0 : WRITE_PUBKEY( self->v1_14_11.authorized_withdrawer, &out, &out_sz );
919 0 : WRITE_U8( self->v1_14_11.commission, &out, &out_sz );
920 0 : CHECK( !ser_votes( self->v1_14_11.votes, 1, &out, &out_sz ) ); /* v1_14_11 wire format is Lockout, not LandedVote */
921 0 : CHECK( !ser_root_slot( self->v1_14_11.has_root_slot, self->v1_14_11.root_slot, &out, &out_sz ) );
922 0 : CHECK( !ser_authorized_voters( self->v1_14_11.authorized_voters.pool, self->v1_14_11.authorized_voters.treap, &out, &out_sz ) );
923 0 : CHECK( !ser_prior_voters( &self->v1_14_11.prior_voters, &out, &out_sz ) );
924 0 : CHECK( !ser_epoch_credits( self->v1_14_11.epoch_credits, &out, &out_sz ) );
925 0 : WRITE_BYTES( &self->v1_14_11.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
926 0 : break;
927 0 : }
928 :
929 0 : case fd_vote_state_versioned_enum_v3: {
930 0 : WRITE_PUBKEY( self->v3.node_pubkey, &out, &out_sz );
931 0 : WRITE_PUBKEY( self->v3.authorized_withdrawer, &out, &out_sz );
932 0 : WRITE_U8( self->v3.commission, &out, &out_sz );
933 0 : CHECK( !ser_votes( self->v3.votes, 0, &out, &out_sz ) );
934 0 : CHECK( !ser_root_slot( self->v3.has_root_slot, self->v3.root_slot, &out, &out_sz ) );
935 0 : CHECK( !ser_authorized_voters( self->v3.authorized_voters.pool, self->v3.authorized_voters.treap, &out, &out_sz ) );
936 0 : CHECK( !ser_prior_voters( &self->v3.prior_voters, &out, &out_sz ) );
937 0 : CHECK( !ser_epoch_credits( self->v3.epoch_credits, &out, &out_sz ) );
938 0 : WRITE_BYTES( &self->v3.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
939 0 : break;
940 0 : }
941 :
942 1386 : case fd_vote_state_versioned_enum_v4: {
943 1386 : WRITE_PUBKEY( self->v4.node_pubkey, &out, &out_sz );
944 1386 : WRITE_PUBKEY( self->v4.authorized_withdrawer, &out, &out_sz );
945 1386 : WRITE_PUBKEY( self->v4.inflation_rewards_collector, &out, &out_sz );
946 1386 : WRITE_PUBKEY( self->v4.block_revenue_collector, &out, &out_sz );
947 1386 : WRITE_U16( self->v4.inflation_rewards_commission_bps, &out, &out_sz );
948 1386 : WRITE_U16( self->v4.block_revenue_commission_bps, &out, &out_sz );
949 1386 : WRITE_U64( self->v4.pending_delegator_rewards, &out, &out_sz );
950 :
951 : /* Option<[u8; 48]> */
952 1386 : WRITE_OPTION( self->v4.has_bls_pubkey_compressed, &out, &out_sz );
953 1386 : if( self->v4.has_bls_pubkey_compressed ) {
954 105 : WRITE_BYTES( self->v4.bls_pubkey_compressed, FD_BLS_PUBKEY_COMPRESSED_SZ, &out, &out_sz );
955 105 : }
956 :
957 1386 : CHECK( !ser_votes( self->v4.votes, 0, &out, &out_sz ) );
958 1386 : CHECK( !ser_root_slot( self->v4.has_root_slot, self->v4.root_slot, &out, &out_sz ) );
959 1386 : CHECK( !ser_authorized_voters( self->v4.authorized_voters.pool, self->v4.authorized_voters.treap, &out, &out_sz ) );
960 1386 : CHECK( !ser_epoch_credits( self->v4.epoch_credits, &out, &out_sz ) ); /* v4 has no prior_voters */
961 1386 : WRITE_BYTES( &self->v4.last_timestamp, sizeof(fd_vote_block_timestamp_t), &out, &out_sz );
962 1386 : break;
963 1386 : }
964 :
965 1386 : default:
966 0 : return 1;
967 1386 : }
968 :
969 1387 : return 0;
970 1386 : }
971 :
972 : ulong
973 1386 : fd_vote_state_versioned_serialized_size( fd_vote_state_versioned_t const * self ) {
974 1386 : switch( self->kind ) {
975 :
976 0 : case fd_vote_state_versioned_enum_uninitialized:
977 0 : return 4UL;
978 :
979 0 : case fd_vote_state_versioned_enum_v1_14_11: {
980 0 : ulong votes_cnt = self->v1_14_11.votes ? deq_fd_landed_vote_t_cnt( self->v1_14_11.votes ) : 0UL;
981 0 : ulong auth_voters_cnt = self->v1_14_11.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v1_14_11.authorized_voters.treap ) : 0UL;
982 0 : ulong epoch_credits_cnt = self->v1_14_11.epoch_credits ? deq_fd_vote_epoch_credits_t_cnt( self->v1_14_11.epoch_credits ) : 0UL;
983 0 : return WIRE_VOTES_OFF_V1_V3
984 0 : + 8UL + votes_cnt * WIRE_LOCKOUT_SZ
985 0 : + 1UL + (ulong)self->v1_14_11.has_root_slot * 8UL
986 0 : + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
987 0 : + WIRE_PRIOR_VOTERS_SZ
988 0 : + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
989 0 : + sizeof(fd_vote_block_timestamp_t);
990 0 : }
991 :
992 0 : case fd_vote_state_versioned_enum_v3: {
993 0 : ulong votes_cnt = self->v3.votes ? deq_fd_landed_vote_t_cnt( self->v3.votes ) : 0UL;
994 0 : ulong auth_voters_cnt = self->v3.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v3.authorized_voters.treap ) : 0UL;
995 0 : ulong epoch_credits_cnt = self->v3.epoch_credits ? deq_fd_vote_epoch_credits_t_cnt( self->v3.epoch_credits ) : 0UL;
996 0 : return WIRE_VOTES_OFF_V1_V3
997 0 : + 8UL + votes_cnt * WIRE_LANDED_VOTE_SZ
998 0 : + 1UL + (ulong)self->v3.has_root_slot * 8UL
999 0 : + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
1000 0 : + WIRE_PRIOR_VOTERS_SZ
1001 0 : + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
1002 0 : + sizeof(fd_vote_block_timestamp_t);
1003 0 : }
1004 :
1005 1386 : case fd_vote_state_versioned_enum_v4: {
1006 1386 : ulong votes_cnt = self->v4.votes ? deq_fd_landed_vote_t_cnt( self->v4.votes ) : 0UL;
1007 1386 : ulong auth_voters_cnt = self->v4.authorized_voters.treap ? fd_vote_authorized_voters_treap_ele_cnt( self->v4.authorized_voters.treap ) : 0UL;
1008 1386 : ulong epoch_credits_cnt = self->v4.epoch_credits ? deq_fd_vote_epoch_credits_t_cnt( self->v4.epoch_credits ) : 0UL;
1009 1386 : return WIRE_BLS_OFF_V4
1010 1386 : + 1UL + (ulong)self->v4.has_bls_pubkey_compressed * FD_BLS_PUBKEY_COMPRESSED_SZ
1011 1386 : + 8UL + votes_cnt * WIRE_LANDED_VOTE_SZ
1012 1386 : + 1UL + (ulong)self->v4.has_root_slot * 8UL
1013 1386 : + 8UL + auth_voters_cnt * WIRE_AUTH_VOTER_SZ
1014 1386 : + 8UL + epoch_credits_cnt * sizeof(fd_vote_epoch_credits_t)
1015 1386 : + sizeof(fd_vote_block_timestamp_t);
1016 0 : }
1017 :
1018 0 : default:
1019 0 : return 0UL;
1020 1386 : }
1021 1386 : }
1022 :
1023 : /**********************************************************************/
1024 : /* Vote instruction -- per-variant deserializers */
1025 : /**********************************************************************/
1026 :
1027 : static int
1028 : deser_vote_authorize( fd_vote_authorize_t * out,
1029 : uchar const ** data,
1030 1127 : ulong * sz ) {
1031 1127 : READ_ENUM( out->discriminant, 3U, data, sz );
1032 1117 : if( out->discriminant==fd_vote_authorize_enum_voter_with_bls ) {
1033 199 : READ_BYTES( out->voter_with_bls.bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ, data, sz );
1034 193 : READ_BYTES( out->voter_with_bls.bls_proof_of_possession, FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ, data, sz );
1035 193 : }
1036 1105 : return 0;
1037 1117 : }
1038 :
1039 : static int
1040 : deser_vote_init( fd_vote_init_t * out,
1041 : uchar const ** data,
1042 233 : ulong * sz ) {
1043 233 : READ_BYTES( out, sizeof(fd_vote_init_t), data, sz );
1044 190 : return 0;
1045 233 : }
1046 :
1047 : static int
1048 : deser_vote_init_v2( fd_vote_init_v2_t * out,
1049 : uchar const ** data,
1050 1 : ulong * sz ) {
1051 1 : READ_PUBKEY( out->node_pubkey, data, sz );
1052 1 : READ_PUBKEY( out->authorized_voter, data, sz );
1053 1 : READ_BYTES( out->authorized_voter_bls_pubkey, FD_BLS_PUBKEY_COMPRESSED_SZ, data, sz );
1054 1 : READ_BYTES( out->authorized_voter_bls_proof_of_possession, FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ, data, sz );
1055 1 : READ_PUBKEY( out->authorized_withdrawer, data, sz );
1056 1 : READ_U16( out->inflation_rewards_commission_bps, data, sz );
1057 1 : READ_PUBKEY( out->inflation_rewards_collector, data, sz );
1058 1 : READ_U16( out->block_revenue_commission_bps, data, sz );
1059 1 : READ_PUBKEY( out->block_revenue_collector, data, sz );
1060 1 : return 0;
1061 1 : }
1062 :
1063 : static int
1064 : deser_vote( fd_vote_t * out,
1065 : uchar const ** data,
1066 575 : ulong * sz ) {
1067 575 : ulong slots_len;
1068 575 : READ_U64( slots_len, data, sz );
1069 573 : CHECK( slots_len<=FD_VOTE_INSTR_MAX_SLOT_NUMS_LEN );
1070 :
1071 568 : out->slots = deq_ulong_join( deq_ulong_new( out->slots_mem, FD_VOTE_INSTR_MAX_SLOT_NUMS_LEN ) );
1072 :
1073 29349 : for( ulong i=0UL; i<slots_len; i++ ) {
1074 28811 : ulong * elem = deq_ulong_push_tail_nocopy( out->slots );
1075 28811 : READ_U64( *elem, data, sz );
1076 28811 : }
1077 :
1078 538 : READ_HASH( out->hash, data, sz );
1079 529 : READ_OPTION( out->has_timestamp, data, sz );
1080 524 : if( out->has_timestamp ) {
1081 245 : READ_I64( out->timestamp, data, sz );
1082 245 : }
1083 520 : return 0;
1084 524 : }
1085 :
1086 : static int
1087 : deser_vote_state_update( fd_vote_state_update_t * out,
1088 : uchar const ** data,
1089 896 : ulong * sz ) {
1090 896 : ulong lockouts_len;
1091 896 : READ_U64( lockouts_len, data, sz );
1092 896 : CHECK( lockouts_len<=FD_VOTE_INSTR_MAX_LOCKOUTS_LEN );
1093 :
1094 892 : out->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( out->lockouts_mem, FD_VOTE_INSTR_MAX_LOCKOUTS_LEN ) );
1095 :
1096 35388 : for( ulong i=0; i<lockouts_len; i++ ) {
1097 34543 : fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( out->lockouts );
1098 34543 : READ_U64( elem->slot, data, sz );
1099 34543 : READ_U32( elem->confirmation_count, data, sz );
1100 34543 : }
1101 :
1102 845 : READ_OPTION( out->has_root, data, sz );
1103 841 : if( out->has_root ) {
1104 301 : READ_U64( out->root, data, sz );
1105 301 : }
1106 837 : READ_HASH( out->hash, data, sz );
1107 825 : READ_OPTION( out->has_timestamp, data, sz );
1108 820 : if( out->has_timestamp ) {
1109 382 : READ_I64( out->timestamp, data, sz );
1110 382 : }
1111 816 : return 0;
1112 820 : }
1113 :
1114 : /* This function contains slightly custom deserialization logic to
1115 : adhere to serde_compact_vote_state_update in Agave.
1116 : https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.1.1/vote-interface/src/state/mod.rs#L265-L299 */
1117 : static int
1118 : deser_compact_vote_state_update( fd_compact_vote_state_update_t * out,
1119 : uchar const ** data,
1120 262 : ulong * sz ) {
1121 262 : READ_U64( out->root, data, sz );
1122 :
1123 261 : ushort lockouts_len;
1124 261 : READ_COMPACT_U16( lockouts_len, data, sz );
1125 253 : CHECK( lockouts_len<=FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN );
1126 233 : out->lockouts_len = lockouts_len;
1127 :
1128 233 : out->lockouts = (fd_lockout_offset_t *)out->lockouts_mem;
1129 :
1130 233 : ulong slot = out->root!=ULONG_MAX ? out->root : 0UL;
1131 5031 : for( ushort i=0; i<lockouts_len; i++ ) {
1132 4822 : READ_U64_VARINT( out->lockouts[i].offset, data, sz );
1133 4819 : READ_U8( out->lockouts[i].confirmation_count, data, sz );
1134 :
1135 : /* Custom logic: check that slot+lockout_offset
1136 : does not overflow */
1137 4818 : CHECK( !__builtin_uaddl_overflow( slot, out->lockouts[i].offset, &slot ) );
1138 4818 : }
1139 :
1140 209 : READ_HASH( out->hash, data, sz );
1141 208 : READ_OPTION( out->has_timestamp, data, sz );
1142 129 : if( out->has_timestamp ) {
1143 63 : READ_I64( out->timestamp, data, sz );
1144 63 : }
1145 127 : return 0;
1146 129 : }
1147 :
1148 : /* Similar to above. Tower sync uses delta-encoded lockout offsets,
1149 : converting them to absolute slot numbers on the fly. Mirrors the
1150 : checked arithmetic from Agave's custom deserializer:
1151 : https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.1.1/vote-interface/src/state/mod.rs#L360-L396 */
1152 :
1153 : static int
1154 : deser_tower_sync( fd_tower_sync_t * out,
1155 : uchar const ** data,
1156 831 : ulong * sz ) {
1157 831 : READ_U64( out->root, data, sz );
1158 830 : out->has_root = 1;
1159 :
1160 : /* First bit of custom logic: if root is ULONG_MAX, set root to 0. */
1161 830 : if( FD_UNLIKELY( out->root==ULONG_MAX ) ) {
1162 256 : out->has_root = 0;
1163 256 : out->root = 0UL;
1164 256 : }
1165 :
1166 830 : ushort lockout_offsets_len;
1167 830 : READ_COMPACT_U16( lockout_offsets_len, data, sz );
1168 765 : CHECK( lockout_offsets_len<=FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN );
1169 :
1170 740 : out->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( out->lockouts_mem, FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN ) );
1171 :
1172 740 : ulong last_slot = out->root;
1173 27825 : for( ushort i=0; i<lockout_offsets_len; i++ ) {
1174 27131 : fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( out->lockouts );
1175 :
1176 27131 : ulong offset;
1177 27131 : READ_U64_VARINT( offset, data, sz );
1178 :
1179 27106 : uchar confirmation_count;
1180 27106 : READ_U8( confirmation_count, data, sz );
1181 :
1182 : /* Second bit of custom logic: check that last_slot+offset does not
1183 : overflow */
1184 27102 : CHECK( !__builtin_uaddl_overflow( last_slot, offset, &elem->slot ) );
1185 27085 : elem->confirmation_count = (uint)confirmation_count;
1186 27085 : last_slot = elem->slot;
1187 27085 : }
1188 :
1189 694 : out->lockouts_cnt = (ulong)lockout_offsets_len;
1190 :
1191 694 : READ_HASH( out->hash, data, sz );
1192 691 : READ_OPTION( out->has_timestamp, data, sz );
1193 689 : if( out->has_timestamp ) {
1194 486 : READ_I64( out->timestamp, data, sz );
1195 486 : }
1196 688 : READ_HASH( out->block_id, data, sz );
1197 687 : return 0;
1198 688 : }
1199 :
1200 : static int
1201 : deser_vote_authorize_with_seed( fd_vote_authorize_with_seed_args_t * out,
1202 : uchar const ** data,
1203 255 : ulong * sz ) {
1204 255 : CHECK( !deser_vote_authorize( &out->authorization_type, data, sz ) );
1205 248 : READ_PUBKEY( out->current_authority_derived_key_owner, data, sz );
1206 :
1207 243 : ulong seed_len;
1208 243 : READ_U64( seed_len, data, sz );
1209 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L42-L49 */
1210 242 : CHECK( seed_len<=FD_VOTE_INSTR_SEED_MAX );
1211 242 : out->current_authority_derived_key_seed_len = seed_len;
1212 :
1213 242 : READ_BYTES( out->current_authority_derived_key_seed, seed_len, data, sz );
1214 241 : CHECK( fd_utf8_verify( (char const *)out->current_authority_derived_key_seed, seed_len ) );
1215 :
1216 201 : READ_PUBKEY( out->new_authority, data, sz );
1217 200 : return 0;
1218 201 : }
1219 :
1220 : static int
1221 : deser_vote_authorize_checked_with_seed( fd_vote_authorize_checked_with_seed_args_t * out,
1222 : uchar const ** data,
1223 259 : ulong * sz ) {
1224 259 : CHECK( !deser_vote_authorize( &out->authorization_type, data, sz ) );
1225 255 : READ_PUBKEY( out->current_authority_derived_key_owner, data, sz );
1226 :
1227 255 : ulong seed_len;
1228 255 : READ_U64( seed_len, data, sz );
1229 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L130 */
1230 254 : CHECK( seed_len<=FD_VOTE_INSTR_SEED_MAX );
1231 242 : out->current_authority_derived_key_seed_len = seed_len;
1232 :
1233 242 : READ_BYTES( out->current_authority_derived_key_seed, seed_len, data, sz );
1234 239 : CHECK( fd_utf8_verify( (char const *)out->current_authority_derived_key_seed, seed_len ) );
1235 174 : return 0;
1236 239 : }
1237 :
1238 : /**********************************************************************/
1239 : /* Vote instruction -- top-level decoder */
1240 : /**********************************************************************/
1241 :
1242 : /* FD_VOTE_INSTR_PREFIX_SZ covers the discriminant and every scalar
1243 : field of every union member. The rest is deque / seed storage the
1244 : decoder fills up to the decoded count, which is all consumers read. */
1245 :
1246 5292 : #define FD_VOTE_INSTR_PREFIX_SZ (320UL)
1247 :
1248 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, vote.slots_mem )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1249 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, update_vote_state.lockouts_mem )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1250 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, compact_update_vote_state.lockouts_mem )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1251 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, tower_sync.lockouts_mem )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1252 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, authorize_with_seed.current_authority_derived_key_seed )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1253 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, authorize_checked_with_seed.current_authority_derived_key_seed )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1254 : FD_STATIC_ASSERT( offsetof( fd_vote_instruction_t, initialize_account_v2 )+sizeof( fd_vote_init_v2_t )<=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1255 : FD_STATIC_ASSERT( sizeof( fd_vote_instruction_t )>=FD_VOTE_INSTR_PREFIX_SZ, vote_instr_prefix );
1256 :
1257 : static int
1258 : fd_vote_instruction_deserialize_inner( fd_vote_instruction_t * instruction,
1259 : uchar const * data,
1260 5292 : ulong data_sz ) {
1261 : /* Zero the scalar prefix only; with handholding, poison the 10 KiB
1262 : tail so a read past the decoded count shows up. */
1263 5292 : fd_memset( instruction, 0, FD_VOTE_INSTR_PREFIX_SZ );
1264 : #if FD_TMPL_USE_HANDHOLDING
1265 : fd_memset( (uchar *)instruction+FD_VOTE_INSTR_PREFIX_SZ, 0xA5, sizeof(fd_vote_instruction_t)-FD_VOTE_INSTR_PREFIX_SZ );
1266 : #endif
1267 :
1268 5292 : uchar const ** p = &data;
1269 5292 : ulong * sz = &data_sz;
1270 :
1271 5292 : READ_U32( instruction->discriminant, p, sz );
1272 :
1273 5277 : switch( instruction->discriminant ) {
1274 :
1275 233 : case fd_vote_instruction_enum_initialize_account:
1276 233 : return deser_vote_init( &instruction->initialize_account, p, sz );
1277 :
1278 325 : case fd_vote_instruction_enum_authorize: {
1279 325 : READ_PUBKEY( instruction->authorize.pubkey, p, sz );
1280 313 : return deser_vote_authorize( &instruction->authorize.vote_authorize, p, sz );
1281 325 : }
1282 :
1283 297 : case fd_vote_instruction_enum_vote:
1284 297 : return deser_vote( &instruction->vote, p, sz );
1285 :
1286 368 : case fd_vote_instruction_enum_withdraw:
1287 368 : READ_U64( instruction->withdraw, p, sz );
1288 367 : return 0;
1289 :
1290 402 : case fd_vote_instruction_enum_update_validator_identity:
1291 402 : return 0;
1292 :
1293 496 : case fd_vote_instruction_enum_update_commission:
1294 496 : READ_U8( instruction->update_commission, p, sz );
1295 494 : return 0;
1296 :
1297 278 : case fd_vote_instruction_enum_vote_switch:
1298 278 : CHECK( !deser_vote( &instruction->vote_switch.vote, p, sz ) );
1299 250 : READ_HASH( instruction->vote_switch.hash, p, sz );
1300 245 : return 0;
1301 :
1302 300 : case fd_vote_instruction_enum_authorize_checked:
1303 300 : return deser_vote_authorize( &instruction->authorize_checked, p, sz );
1304 :
1305 448 : case fd_vote_instruction_enum_update_vote_state:
1306 448 : return deser_vote_state_update( &instruction->update_vote_state, p, sz );
1307 :
1308 449 : case fd_vote_instruction_enum_update_vote_state_switch:
1309 449 : CHECK( !deser_vote_state_update( &instruction->update_vote_state_switch.vote_state_update, p, sz ) );
1310 403 : READ_HASH( instruction->update_vote_state_switch.hash, p, sz );
1311 392 : return 0;
1312 :
1313 255 : case fd_vote_instruction_enum_authorize_with_seed:
1314 255 : return deser_vote_authorize_with_seed( &instruction->authorize_with_seed, p, sz );
1315 :
1316 259 : case fd_vote_instruction_enum_authorize_checked_with_seed:
1317 259 : return deser_vote_authorize_checked_with_seed( &instruction->authorize_checked_with_seed, p, sz );
1318 :
1319 144 : case fd_vote_instruction_enum_compact_update_vote_state:
1320 144 : return deser_compact_vote_state_update( &instruction->compact_update_vote_state, p, sz );
1321 :
1322 118 : case fd_vote_instruction_enum_compact_update_vote_state_switch:
1323 118 : CHECK( !deser_compact_vote_state_update( &instruction->compact_update_vote_state_switch.compact_vote_state_update, p, sz ) );
1324 64 : READ_HASH( instruction->compact_update_vote_state_switch.hash, p, sz );
1325 62 : return 0;
1326 :
1327 547 : case fd_vote_instruction_enum_tower_sync:
1328 547 : return deser_tower_sync( &instruction->tower_sync, p, sz );
1329 :
1330 284 : case fd_vote_instruction_enum_tower_sync_switch:
1331 284 : CHECK( !deser_tower_sync( &instruction->tower_sync_switch.tower_sync, p, sz ) );
1332 199 : READ_HASH( instruction->tower_sync_switch.hash, p, sz );
1333 195 : return 0;
1334 :
1335 1 : case fd_vote_instruction_enum_initialize_account_v2:
1336 1 : return deser_vote_init_v2( &instruction->initialize_account_v2, p, sz );
1337 :
1338 0 : case fd_vote_instruction_enum_update_commission_collector:
1339 0 : READ_ENUM( instruction->update_commission_collector.discriminant, 2U, p, sz );
1340 0 : return 0;
1341 :
1342 0 : case fd_vote_instruction_enum_update_commission_bps:
1343 0 : READ_U16( instruction->update_commission_bps.commission_bps, p, sz );
1344 0 : READ_ENUM( instruction->update_commission_bps.kind.discriminant, 2U, p, sz );
1345 0 : return 0;
1346 :
1347 0 : case fd_vote_instruction_enum_deposit_delegator_rewards:
1348 0 : READ_U64( instruction->deposit_delegator_rewards.deposit, p, sz );
1349 0 : return 0;
1350 :
1351 82 : default:
1352 82 : return 1;
1353 5277 : }
1354 5277 : }
1355 :
1356 : fd_vote_instruction_t *
1357 : fd_vote_instruction_deserialize( fd_vote_instruction_t * instruction,
1358 : uchar const * data,
1359 5293 : ulong data_sz ) {
1360 : /* limited_deserialize(data, PACKET_DATA_SIZE)
1361 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.1/programs/vote/src/vote_processor.rs#L130 */
1362 5293 : data_sz = fd_ulong_min( data_sz, FD_TXN_MTU_V0 );
1363 5293 : CHECK_RET_NULL( !fd_vote_instruction_deserialize_inner( instruction, data, data_sz ) );
1364 4551 : return instruction;
1365 5293 : }
|