Line data Source code
1 : #include "fd_vote_program.h"
2 : #include "../fd_runtime.h"
3 : #include "../fd_borrowed_account.h"
4 : #include "../fd_executor.h"
5 : #include "../fd_pubkey_utils.h"
6 : #include "../sysvar/fd_sysvar_rent.h"
7 : #include "../sysvar/fd_sysvar_cache.h"
8 : #include "../sysvar/fd_sysvar.h"
9 : #include "../fd_system_ids.h"
10 : #include "vote/fd_authorized_voters.h"
11 : #include "vote/fd_vote_utils.h"
12 : #include "vote/fd_vote_codec.h"
13 : #include "vote/fd_vote_state_versioned.h"
14 : #include "vote/fd_vote_state_v4.h"
15 : #include "../../../ballet/bls/fd_bls12_381.h"
16 :
17 : #include <limits.h>
18 : #include <math.h>
19 : #include <stdio.h>
20 : #include <string.h>
21 :
22 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L36
23 0 : #define INITIAL_LOCKOUT 2UL
24 :
25 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L51
26 : #define VOTE_CREDITS_MAXIMUM_PER_SLOT_OLD 8
27 :
28 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/clock.rs#L147
29 : #define SLOT_DEFAULT 0UL
30 :
31 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/clock.rs#L147
32 : #define SLOT_MAX ULONG_MAX
33 :
34 : #define ACCOUNTS_MAX 4 /* Vote instructions take in at most 4 accounts */
35 :
36 : #define DEFAULT_COMPUTE_UNITS 2100UL
37 : #define COMPUTE_UNITS_POP 34500UL
38 :
39 : /**********************************************************************/
40 : /* VoteStateHandler */
41 : /**********************************************************************/
42 :
43 : /* Check the vote state, deserialize it as V4 and convert older versions
44 : to V4 in-place.
45 : https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_state/mod.rs#L45-L77 */
46 : static int
47 : get_vote_state_handler_checked( fd_borrowed_account_t const * vote_account,
48 : int target_version,
49 : uchar check_initialized,
50 78 : fd_vote_state_versioned_t * vote_state_versioned ) {
51 78 : (void)target_version;
52 78 : (void)check_initialized; /* V4 vote states are always initialized */
53 :
54 78 : int rc = fd_vsv_deserialize( vote_account->acc, vote_state_versioned );
55 78 : if( FD_UNLIKELY( rc ) ) return rc;
56 :
57 66 : if( FD_UNLIKELY( fd_vsv_is_uninitialized( vote_state_versioned ) ) ) {
58 3 : return FD_EXECUTOR_INSTR_ERR_UNINITIALIZED_ACCOUNT;
59 3 : }
60 :
61 63 : rc = fd_vsv_try_convert_to_v4( vote_state_versioned, (fd_pubkey_t*)vote_account->acc->pubkey );
62 63 : if( FD_UNLIKELY( rc ) ) return rc;
63 :
64 63 : return FD_EXECUTOR_INSTR_SUCCESS;
65 63 : }
66 :
67 : /* https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_state/handler.rs#L379-L393 */
68 : static int
69 : check_vote_account_length( fd_borrowed_account_t const * vote_account,
70 24 : int target_version ) {
71 24 : (void)target_version;
72 24 : ulong length = fd_borrowed_account_get_data_len( vote_account );
73 24 : if( FD_UNLIKELY( length!=FD_VOTE_STATE_V4_SZ ) ) {
74 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
75 0 : }
76 24 : return FD_EXECUTOR_INSTR_SUCCESS;
77 24 : }
78 :
79 : /* https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_state/handler.rs#L327-L342 */
80 : static int
81 : init_vote_account_state( fd_exec_instr_ctx_t * ctx,
82 : fd_borrowed_account_t * vote_account,
83 : fd_vote_state_versioned_t * versioned,
84 : int target_version,
85 : fd_vote_init_t * vote_init,
86 24 : fd_sol_sysvar_clock_t const * clock ) {
87 24 : (void)target_version;
88 24 : fd_vote_state_v4_create_new_with_defaults( (fd_pubkey_t*)vote_account->acc->pubkey, vote_init, clock, versioned );
89 24 : return fd_vote_state_v4_set_vote_account_state( ctx, vote_account, versioned );
90 24 : }
91 :
92 : /* https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_state/handler.rs#L344-L362 */
93 : static int
94 : init_vote_account_state_v2( fd_exec_instr_ctx_t * ctx,
95 : fd_borrowed_account_t * vote_account,
96 : fd_vote_state_versioned_t * versioned,
97 : int target_version,
98 : fd_vote_init_v2_t * vote_init_v2,
99 0 : fd_sol_sysvar_clock_t const * clock ) {
100 0 : (void)target_version;
101 0 : fd_vote_state_v4_create_new( vote_init_v2, clock, versioned );
102 0 : return fd_vote_state_v4_set_vote_account_state( ctx, vote_account, versioned );
103 0 : }
104 :
105 : /**********************************************************************/
106 : /* mod vote_state */
107 : /**********************************************************************/
108 :
109 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L82-L324 */
110 : static int
111 : check_and_filter_proposed_vote_state( fd_exec_instr_ctx_t * ctx,
112 : fd_vote_state_versioned_t * versioned,
113 : fd_vote_lockout_t * proposed_lockouts,
114 : uchar * proposed_has_root,
115 : ulong * proposed_root,
116 : fd_hash_t const * proposed_hash,
117 0 : fd_slot_hashes_t const * slot_hashes ) {
118 0 : fd_landed_vote_t const * votes = fd_vsv_get_votes( versioned );
119 0 : ulong const * root_slot = fd_vsv_get_root_slot( versioned );
120 0 : uchar has_root_slot = !!(root_slot!=NULL);
121 :
122 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L208
123 0 : if( FD_UNLIKELY( deq_fd_vote_lockout_t_empty( proposed_lockouts ) ) ) {
124 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
125 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
126 0 : }
127 0 : fd_landed_vote_t const * last_vote = NULL;
128 0 : if( !deq_fd_landed_vote_t_empty( votes ) ) {
129 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L212
130 0 : last_vote = deq_fd_landed_vote_t_peek_tail_const( votes );
131 0 : }
132 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L218
133 0 : if( FD_LIKELY( last_vote ) ) {
134 0 : if( FD_UNLIKELY( deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot <=
135 0 : last_vote->lockout.slot ) ) {
136 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTE_TOO_OLD;
137 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
138 0 : }
139 0 : }
140 :
141 : /* must be nonempty, checked above */
142 0 : ulong last_vote_state_update_slot = deq_fd_vote_lockout_t_peek_tail_const( proposed_lockouts )->slot;
143 :
144 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L224
145 0 : if( FD_UNLIKELY( !slot_hashes->cnt ) ) {
146 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
147 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
148 0 : }
149 :
150 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L227
151 0 : ulong earliest_slot_hash_in_history = slot_hashes->elems[ slot_hashes->cnt-1UL ].slot;
152 :
153 : /* Check if the proposed vote is too old to be in the SlotHash history */
154 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L230
155 0 : if( FD_UNLIKELY( last_vote_state_update_slot < earliest_slot_hash_in_history ) ) {
156 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTE_TOO_OLD;
157 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
158 0 : }
159 :
160 : /* Check if the proposed root is too old */
161 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L237
162 0 : if( *proposed_has_root ) {
163 0 : ulong const proposed_root_ = *proposed_root;
164 : /* If the new proposed root `R` is less than the earliest slot hash in the history
165 : such that we cannot verify whether the slot was actually was on this fork, set
166 : the root to the latest vote in the current vote that's less than R. */
167 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L242
168 0 : if( proposed_root_ < earliest_slot_hash_in_history ) {
169 0 : *proposed_has_root = has_root_slot;
170 0 : if( has_root_slot ) {
171 0 : *proposed_root = *root_slot;
172 0 : }
173 0 : for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init_rev( votes );
174 0 : !deq_fd_landed_vote_t_iter_done_rev( votes, iter );
175 0 : iter = deq_fd_landed_vote_t_iter_prev( votes, iter ) ) {
176 : /* Ensure we're iterating from biggest to smallest vote in the
177 : current vote state */
178 0 : fd_landed_vote_t const * vote = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
179 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L248
180 0 : if( vote->lockout.slot <= proposed_root_ ) {
181 0 : *proposed_has_root = 1;
182 0 : *proposed_root = vote->lockout.slot;
183 0 : break;
184 0 : }
185 0 : }
186 0 : }
187 0 : }
188 :
189 : /* Index into the new proposed vote state's slots, starting with the root if it exists then
190 : we use this mutable root to fold checking the root slot into the below loop for performance */
191 0 : int has_root_to_check = *proposed_has_root;
192 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L259
193 0 : ulong root_to_check = *proposed_root;
194 0 : ulong proposed_lockouts_index = 0UL;
195 0 : ulong lockouts_len = deq_fd_vote_lockout_t_cnt( proposed_lockouts );
196 :
197 : /* Index into the slot_hashes, starting at the oldest known slot hash */
198 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L264
199 0 : ulong slot_hashes_index = slot_hashes->cnt;
200 :
201 : /* proposed_lockouts_indexes_to_filter's size is bounded by the length
202 : of the proposed lockouts provided in the instruction data. */
203 0 : ulong proposed_lockouts_indexes_to_filter[ FD_VOTE_INSTR_MAX_LOCKOUT_OFFSETS_LEN ];
204 0 : ulong filter_index = 0UL;
205 :
206 : /* Note:
207 :
208 : 1) `vote_state_update.lockouts` is sorted from oldest/smallest vote to newest/largest
209 : vote, due to the way votes are applied to the vote state (newest votes
210 : pushed to the back).
211 :
212 : 2) Conversely, `slot_hashes` is sorted from newest/largest vote to
213 : the oldest/smallest vote.
214 :
215 : Unlike for vote updates, vote state updates here can't only check votes older than the last vote
216 : because have to ensure that every slot is actually part of the history, not just the most
217 : recent ones */
218 :
219 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L279
220 0 : while( proposed_lockouts_index < lockouts_len && slot_hashes_index > 0 ) {
221 0 : ulong proposed_vote_slot =
222 0 : fd_ulong_if( has_root_to_check,
223 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L281
224 0 : root_to_check,
225 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L283
226 0 : deq_fd_vote_lockout_t_peek_index_const( proposed_lockouts,
227 0 : proposed_lockouts_index )
228 0 : ->slot );
229 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L285
230 0 : if( !has_root_to_check && proposed_lockouts_index > 0UL &&
231 0 : proposed_vote_slot <=
232 0 : deq_fd_vote_lockout_t_peek_index_const(
233 0 : proposed_lockouts,
234 0 : fd_ulong_checked_sub_expect(
235 0 : proposed_lockouts_index,
236 0 : 1,
237 0 : "`proposed_lockouts_index` is positive when checking `SlotsNotOrdered`" ) )
238 0 : ->slot ) {
239 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L293
240 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_NOT_ORDERED;
241 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
242 0 : }
243 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L295
244 0 : ulong ancestor_slot =
245 0 : slot_hashes->elems[
246 0 : fd_ulong_checked_sub_expect(
247 0 : slot_hashes_index,
248 0 : 1UL,
249 0 : "`slot_hashes_index` is positive when computing `ancestor_slot`" ) ]
250 0 : .slot;
251 : /* Find if this slot in the proposed vote state exists in the SlotHashes history
252 : to confirm if it was a valid ancestor on this fork */
253 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L303
254 0 : if( proposed_vote_slot < ancestor_slot ) {
255 0 : if( slot_hashes_index == slot_hashes->cnt ) {
256 : /* The vote slot does not exist in the SlotHashes history because it's too old,
257 : i.e. older than the oldest slot in the history. */
258 0 : if( proposed_vote_slot >= earliest_slot_hash_in_history ) {
259 0 : ctx->txn_out->err.custom_err = 0;
260 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
261 0 : }
262 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L310
263 0 : if( !fd_vote_contains_slot( votes, proposed_vote_slot ) && !has_root_to_check ) {
264 : /* If the vote slot is both:
265 : 1) Too old
266 : 2) Doesn't already exist in vote state
267 : Then filter it out */
268 0 : proposed_lockouts_indexes_to_filter[filter_index++] = proposed_lockouts_index; }
269 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L318
270 0 : if( has_root_to_check ) {
271 0 : ulong new_proposed_root = root_to_check;
272 : /* 1. Because `root_to_check.is_some()`, then we know that
273 : we haven't checked the root yet in this loop, so
274 : `proposed_vote_slot` == `new_proposed_root` == `vote_state_update.root` */
275 0 : FD_TEST( new_proposed_root == proposed_vote_slot );
276 : /* 2. We know from the assert earlier in the function that
277 : `proposed_vote_slot < earliest_slot_hash_in_history`,
278 : so from 1. we know that `new_proposed_root < earliest_slot_hash_in_history` */
279 0 : if( new_proposed_root >= earliest_slot_hash_in_history ) {
280 0 : ctx->txn_out->err.custom_err = 0;
281 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
282 0 : }
283 :
284 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L329
285 0 : has_root_to_check = 0;
286 0 : root_to_check = ULONG_MAX;
287 0 : } else {
288 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L331
289 0 : proposed_lockouts_index = fd_ulong_checked_add_expect(
290 0 : proposed_lockouts_index,
291 0 : 1,
292 0 : "`proposed_lockouts_index` is bounded by `MAX_LOCKOUT_HISTORY` when "
293 0 : "`proposed_vote_slot` is too old to be in SlotHashes history" );
294 0 : }
295 0 : continue;
296 0 : } else {
297 : /* If the vote slot is new enough to be in the slot history,
298 : but is not part of the slot history, then it must belong to another fork,
299 : which means this vote state update is invalid. */
300 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L340
301 0 : if( has_root_to_check ) {
302 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_ROOT_ON_DIFFERENT_FORK;
303 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
304 0 : } else {
305 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
306 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
307 0 : }
308 0 : }
309 0 : } else if( proposed_vote_slot > ancestor_slot ) {
310 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L347
311 :
312 : /* Decrement `slot_hashes_index` to find newer slots in the SlotHashes history */
313 0 : slot_hashes_index = fd_ulong_checked_sub_expect(
314 0 : slot_hashes_index,
315 0 : 1,
316 0 : "`slot_hashes_index` is positive when finding newer slots in SlotHashes history" );
317 0 : continue;
318 0 : } else {
319 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L354
320 :
321 : /* Once the slot in `vote_state_update.lockouts` is found, bump to the next slot
322 : in `vote_state_update.lockouts` and continue. If we were checking the root,
323 : start checking the vote state instead. */
324 0 : if( has_root_to_check ) {
325 0 : has_root_to_check = 0;
326 0 : root_to_check = ULONG_MAX;
327 0 : } else {
328 0 : proposed_lockouts_index = fd_ulong_checked_add_expect(
329 0 : proposed_lockouts_index,
330 0 : 1,
331 0 : "`proposed_lockouts_index` is bounded by `MAX_LOCKOUT_HISTORY` "
332 0 : "when match is found in SlotHashes history" );
333 0 : slot_hashes_index = fd_ulong_checked_sub_expect(
334 0 : slot_hashes_index,
335 0 : 1,
336 0 : "`slot_hashes_index` is positive when match is found in SlotHashes history" );
337 0 : }
338 0 : }
339 0 : }
340 :
341 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L372
342 0 : if( proposed_lockouts_index != deq_fd_vote_lockout_t_cnt( proposed_lockouts ) ) {
343 : /* The last vote slot in the update did not exist in SlotHashes */
344 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
345 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
346 0 : }
347 :
348 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L401
349 0 : if( memcmp( &slot_hashes->elems[ slot_hashes_index ].hash,
350 0 : proposed_hash,
351 0 : sizeof( fd_hash_t ) ) != 0 ) {
352 : /* This means the newest vote in the slot has a match that
353 : doesn't match the expected hash for that slot on this fork */
354 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH;
355 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
356 0 : }
357 :
358 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L418
359 : /* Filter out the irrelevant votes */
360 0 : proposed_lockouts_index = 0UL;
361 0 : ulong filter_votes_index = deq_fd_vote_lockout_t_cnt( proposed_lockouts );
362 :
363 : /* We need to iterate backwards here because proposed_lockouts_indexes_to_filter[ i ] is a
364 : strictly increasing value. Forward iterating can lead to the proposed lockout indices to get
365 : shifted leading to popping the wrong proposed lockouts or out of bounds accessing. We need
366 : to be sure of handling underflow in this case. */
367 :
368 0 : for( ulong i=filter_index; i>0UL && filter_votes_index>0UL; i-- ) {
369 0 : proposed_lockouts_index = i - 1UL;
370 0 : if( FD_UNLIKELY( proposed_lockouts_indexes_to_filter[ proposed_lockouts_index ]>=filter_votes_index ) ) {
371 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID;
372 0 : }
373 :
374 0 : deq_fd_vote_lockout_t_pop_idx_tail( proposed_lockouts, proposed_lockouts_indexes_to_filter[ proposed_lockouts_index ] );
375 0 : filter_votes_index--;
376 0 : }
377 :
378 0 : return FD_EXECUTOR_INSTR_SUCCESS;
379 0 : }
380 :
381 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L440
382 : static int
383 : check_slots_are_valid( fd_exec_instr_ctx_t * ctx,
384 : fd_vote_state_versioned_t * versioned,
385 : ulong const * vote_slots,
386 : fd_hash_t const * vote_hash,
387 0 : fd_slot_hashes_t const * slot_hashes ) {
388 0 : ulong i = 0;
389 0 : ulong j = slot_hashes->cnt;
390 0 : ulong vote_slots_len = deq_ulong_cnt( vote_slots );
391 :
392 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L462
393 0 : while( i < vote_slots_len && j > 0 ) {
394 0 : ulong const * last_voted_slot_ = fd_vsv_get_last_voted_slot( versioned );
395 0 : if( FD_UNLIKELY( last_voted_slot_ &&
396 0 : *deq_ulong_peek_index_const( vote_slots, i ) <= *last_voted_slot_ ) ) {
397 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L469
398 0 : i = fd_ulong_checked_add_expect(
399 0 : i, 1, "`i` is bounded by `MAX_LOCKOUT_HISTORY` when finding larger slots" );
400 0 : continue;
401 0 : }
402 :
403 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L476
404 0 : if( FD_UNLIKELY(
405 0 : *deq_ulong_peek_index_const( vote_slots, i ) !=
406 0 : slot_hashes->elems[
407 0 : fd_ulong_checked_sub_expect( j, 1, "`j` is positive" ) ]
408 0 : .slot ) ) {
409 0 : j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when finding newer slots" );
410 0 : continue;
411 0 : }
412 :
413 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L486
414 0 : i = fd_ulong_checked_add_expect(
415 0 : i, 1, "`i` is bounded by `MAX_LOCKOUT_HISTORY` when hash is found" );
416 0 : j = fd_ulong_checked_sub_expect( j, 1, "`j` is positive when hash is found" );
417 0 : }
418 :
419 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L494
420 0 : if( FD_UNLIKELY( j == slot_hashes->cnt ) ) {
421 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTE_TOO_OLD;
422 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
423 0 : }
424 0 : if( FD_UNLIKELY( i != vote_slots_len ) ) {
425 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_MISMATCH;
426 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
427 0 : }
428 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L514
429 0 : if( FD_UNLIKELY( 0 != memcmp( &slot_hashes->elems[ j ].hash,
430 0 : vote_hash,
431 0 : 32UL ) ) ) {
432 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_HASH_MISMATCH;
433 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
434 0 : }
435 0 : return 0;
436 0 : }
437 :
438 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L565
439 : static int
440 : process_new_vote_state( fd_exec_instr_ctx_t * ctx,
441 : fd_vote_state_versioned_t * versioned,
442 : fd_landed_vote_t * new_state,
443 : int has_new_root,
444 : ulong new_root,
445 : int has_timestamp,
446 : long timestamp,
447 : ulong epoch,
448 0 : ulong current_slot ) {
449 0 : int rc;
450 0 : fd_landed_vote_t * votes = fd_vsv_get_votes_mutable( versioned );
451 0 : ulong const * root_slot = fd_vsv_get_root_slot( versioned );
452 0 : uchar has_root_slot = !!(root_slot!=NULL);
453 :
454 0 : FD_TEST( !deq_fd_landed_vote_t_empty( new_state ) );
455 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L575
456 0 : if( FD_UNLIKELY( deq_fd_landed_vote_t_cnt( new_state ) > MAX_LOCKOUT_HISTORY ) ) {
457 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_TOO_MANY_VOTES;
458 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
459 0 : };
460 :
461 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L579
462 0 : if( FD_UNLIKELY( has_new_root && has_root_slot ) ) {
463 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L581
464 0 : if( FD_UNLIKELY( new_root<*root_slot ) ) {
465 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_ROOT_ROLL_BACK;
466 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
467 0 : }
468 0 : } else if( FD_UNLIKELY( !has_new_root && has_root_slot ) ) {
469 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L586
470 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_ROOT_ROLL_BACK;
471 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
472 0 : } else {
473 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L588
474 : /* no-op */
475 0 : }
476 :
477 0 : fd_landed_vote_t * previous_vote = NULL;
478 0 : for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
479 0 : !deq_fd_landed_vote_t_iter_done( new_state, iter );
480 0 : iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
481 0 : fd_landed_vote_t * vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
482 0 : if( FD_LIKELY( vote->lockout.confirmation_count == 0 ) ) {
483 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_ZERO_CONFIRMATIONS;
484 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
485 0 : } else if( FD_UNLIKELY( vote->lockout.confirmation_count > MAX_LOCKOUT_HISTORY ) ) {
486 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_CONFIRMATION_TOO_LARGE;
487 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
488 0 : } else if( FD_LIKELY( has_new_root ) ) {
489 0 : if( FD_UNLIKELY( vote->lockout.slot <= new_root && new_root != SLOT_DEFAULT ) ) {
490 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOT_SMALLER_THAN_ROOT;
491 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
492 0 : }
493 0 : }
494 :
495 0 : if( FD_LIKELY( previous_vote ) ) {
496 0 : if( FD_UNLIKELY( previous_vote->lockout.slot >= vote->lockout.slot ) ) {
497 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_SLOTS_NOT_ORDERED;
498 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
499 0 : } else if( FD_UNLIKELY( previous_vote->lockout.confirmation_count <=
500 0 : vote->lockout.confirmation_count ) ) {
501 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_CONFIRMATIONS_NOT_ORDERED;
502 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
503 0 : } else if( FD_UNLIKELY( vote->lockout.slot >
504 0 : fd_vote_lockout_last_locked_out_slot( &previous_vote->lockout ) ) ) {
505 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_NEW_VOTE_STATE_LOCKOUT_MISMATCH;
506 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
507 0 : }
508 0 : }
509 0 : previous_vote = vote;
510 0 : }
511 :
512 0 : ulong current_vote_state_index = 0;
513 0 : ulong new_vote_state_index = 0;
514 :
515 : /* Accumulate credits earned by newly rooted slots. The behavior changes with
516 : timely_vote_credits: prior to this feature, there was a bug that counted a new root slot as 1
517 : credit even if it had never been voted on. timely_vote_credits fixes this bug by only awarding
518 : credits for slots actually voted on and finalized. */
519 :
520 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L635
521 :
522 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L641
523 0 : ulong earned_credits = 0;
524 :
525 0 : if( FD_LIKELY( has_new_root ) ) {
526 0 : for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( votes );
527 0 : !deq_fd_landed_vote_t_iter_done( votes, iter );
528 0 : iter = deq_fd_landed_vote_t_iter_next( votes, iter ) ) {
529 0 : fd_landed_vote_t const * current_vote = deq_fd_landed_vote_t_iter_ele_const( votes, iter );
530 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L647
531 0 : if( FD_UNLIKELY( current_vote->lockout.slot <= new_root ) ) {
532 : // this is safe because we're inside if has_new_root
533 0 : earned_credits = fd_ulong_checked_add_expect(
534 0 : fd_vote_credits_for_vote_at_index(
535 0 : votes,
536 0 : current_vote_state_index
537 0 : ),
538 0 : earned_credits,
539 0 : "`earned_credits` does not overflow" );
540 0 : current_vote_state_index = fd_ulong_checked_add_expect(
541 0 : current_vote_state_index,
542 0 : 1,
543 0 : "`current_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
544 0 : "when processing new root" );
545 0 : continue;
546 0 : }
547 0 : break;
548 0 : }
549 0 : }
550 :
551 : // For any slots newly added to the new vote state, the vote latency of that slot is not provided by the
552 : // vote instruction contents, but instead is computed from the actual latency of the vote
553 : // instruction. This prevents other validators from manipulating their own vote latencies within their vote states
554 : // and forcing the rest of the cluster to accept these possibly fraudulent latency values. If the
555 : // timly_vote_credits feature is not enabled then vote latency is set to 0 for new votes.
556 : //
557 : // For any slot that is in both the new state and the current state, the vote latency of the new state is taken
558 : // from the current state.
559 : //
560 : // Thus vote latencies are set here for any newly vote-on slots when a vote instruction is received.
561 : // They are copied into the new vote state after every vote for already voted-on slots.
562 : // And when voted-on slots are rooted, the vote latencies stored in the vote state of all the rooted slots is used
563 : // to compute credits earned.
564 : // All validators compute the same vote latencies because all process the same vote instruction at the
565 : // same slot, and the only time vote latencies are ever computed is at the time that their slot is first voted on;
566 : // after that, the latencies are retained unaltered until the slot is rooted.
567 :
568 : // All the votes in our current vote state that are missing from the new vote state
569 : // must have been expired by later votes. Check that the lockouts match this assumption.
570 :
571 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L686
572 0 : while( current_vote_state_index < deq_fd_landed_vote_t_cnt( votes ) &&
573 0 : new_vote_state_index < deq_fd_landed_vote_t_cnt( new_state ) ) {
574 0 : fd_landed_vote_t const * current_vote = deq_fd_landed_vote_t_peek_index_const( votes, current_vote_state_index );
575 :
576 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L690
577 0 : fd_landed_vote_t * new_vote =
578 0 : deq_fd_landed_vote_t_peek_index( new_state, new_vote_state_index );
579 :
580 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L696
581 0 : if( FD_LIKELY( current_vote->lockout.slot < new_vote->lockout.slot ) ) {
582 : /* The agave implementation of calculating the last locked out
583 : slot does not calculate a min between the current vote's
584 : confirmation count and max lockout history. The reason we do
585 : this is to make sure that the fuzzers continue working:
586 : the max lockout history can not be > MAX_LOCKOUT_HISTORY. */
587 0 : ulong confirmation_count = fd_ulong_min( current_vote->lockout.confirmation_count, MAX_LOCKOUT_HISTORY );
588 0 : ulong last_locked_out_slot = fd_ulong_sat_add( current_vote->lockout.slot,
589 0 : (ulong)pow( INITIAL_LOCKOUT, (double)confirmation_count ) );
590 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L697
591 0 : if( last_locked_out_slot >= new_vote->lockout.slot ) {
592 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L698
593 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_LOCKOUT_CONFLICT;
594 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
595 0 : }
596 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L700
597 0 : current_vote_state_index =
598 0 : fd_ulong_checked_add_expect( current_vote_state_index,
599 0 : 1,
600 0 : "`current_vote_state_index` is bounded by "
601 0 : "`MAX_LOCKOUT_HISTORY` when slot is less than proposed" );
602 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L704
603 0 : } else if( FD_UNLIKELY( current_vote->lockout.slot == new_vote->lockout.slot ) ) {
604 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L707
605 0 : if( new_vote->lockout.confirmation_count < current_vote->lockout.confirmation_count ) {
606 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_CONFIRMATION_ROLL_BACK;
607 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
608 0 : }
609 :
610 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L712
611 0 : new_vote->latency = deq_fd_landed_vote_t_peek_index_const( votes, current_vote_state_index )->latency;
612 :
613 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L714
614 0 : current_vote_state_index =
615 0 : fd_ulong_checked_add_expect( current_vote_state_index,
616 0 : 1,
617 0 : "`current_vote_state_index` is bounded by "
618 0 : "`MAX_LOCKOUT_HISTORY` when slot is equal to proposed" );
619 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L717
620 0 : new_vote_state_index =
621 0 : fd_ulong_checked_add_expect( new_vote_state_index,
622 0 : 1,
623 0 : "`new_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
624 0 : "when slot is equal to proposed" );
625 0 : } else {
626 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L722
627 0 : new_vote_state_index =
628 0 : fd_ulong_checked_add_expect( new_vote_state_index,
629 0 : 1,
630 0 : "`new_vote_state_index` is bounded by `MAX_LOCKOUT_HISTORY` "
631 0 : "when slot is greater than proposed" );
632 0 : }
633 0 : }
634 :
635 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L737
636 0 : for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
637 0 : !deq_fd_landed_vote_t_iter_done( new_state, iter );
638 0 : iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
639 0 : fd_landed_vote_t * new_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
640 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L738
641 0 : if( FD_UNLIKELY( new_vote->latency == 0 ) ) {
642 : // this is unlikely because as validators upgrade, it should converge to the new vote state
643 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L739
644 0 : new_vote->latency = fd_vote_compute_vote_latency( new_vote->lockout.slot, current_slot );
645 0 : }
646 0 : }
647 :
648 : // doesn't matter what the value of slot if `is_some = 0` i.e. `Option::None`
649 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L744
650 0 : int both_none = !has_root_slot && !has_new_root;
651 0 : if( ( !both_none && ( has_root_slot!=has_new_root ||
652 0 : *root_slot!=new_root ) ) ) {
653 0 : fd_vsv_increment_credits( versioned, epoch, earned_credits );
654 0 : }
655 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L750
656 0 : if( FD_LIKELY( has_timestamp ) ) {
657 : /* new_state asserted nonempty at function beginning */
658 0 : if( FD_UNLIKELY( deq_fd_landed_vote_t_empty( new_state ) ) ) {
659 0 : FD_LOG_CRIT(( "invariant violation: landed votes is empty" ));
660 0 : }
661 0 : ulong last_slot = deq_fd_landed_vote_t_peek_tail( new_state )->lockout.slot;
662 0 : rc = fd_vsv_process_timestamp( ctx, versioned, last_slot, timestamp );
663 0 : if( FD_UNLIKELY( rc ) ) { return rc; }
664 0 : }
665 :
666 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L754
667 0 : fd_vsv_set_root_slot( versioned, has_new_root ? &new_root : NULL );
668 :
669 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L755
670 0 : deq_fd_landed_vote_t_remove_all( votes );
671 0 : for( deq_fd_landed_vote_t_iter_t iter = deq_fd_landed_vote_t_iter_init( new_state );
672 0 : !deq_fd_landed_vote_t_iter_done( new_state, iter );
673 0 : iter = deq_fd_landed_vote_t_iter_next( new_state, iter ) ) {
674 0 : fd_landed_vote_t * landed_vote = deq_fd_landed_vote_t_iter_ele( new_state, iter );
675 0 : deq_fd_landed_vote_t_push_tail_wrap( votes, *landed_vote );
676 0 : }
677 :
678 0 : return FD_EXECUTOR_INSTR_SUCCESS;
679 0 : }
680 :
681 : __attribute__((weak)) int
682 : fd_bls12_381_proof_of_possession_verify( uchar const msg[],
683 : ulong msg_sz,
684 : uchar const proof[ static FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ ],
685 0 : uchar const public_key[ static FD_BLS_PUBKEY_COMPRESSED_SZ ] ) {
686 0 : (void)msg; (void)msg_sz; (void)proof; (void)public_key;
687 0 : FD_LOG_ERR(( "This build does not include BLST, which is required to run a validator.\n"
688 0 : "To install BLST, re-run ./deps.sh, make distclean, and make -j" ));
689 0 : }
690 :
691 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1059-L1108 */
692 : #define FD_VOTE_BLS_MSG_SZ ( 9 + 32 + 48 )
693 : static int
694 : fd_vote_verify_bls_proof_of_possession( fd_exec_instr_ctx_t * ctx,
695 : uchar const vote_account_pubkey[ static 32 ],
696 : uchar const bls_pubkey[ static FD_BLS_PUBKEY_COMPRESSED_SZ ],
697 0 : uchar const bls_proof[ static FD_BLS_PROOF_OF_POSSESSION_COMPRESSED_SZ ] ) {
698 : /* Consume CUs for proof of possession */
699 0 : FD_EXEC_CU_UPDATE( ctx, COMPUTE_UNITS_POP );
700 :
701 : /* Build message */
702 0 : uchar msg[ FD_VOTE_BLS_MSG_SZ ];
703 0 : memcpy( msg, "ALPENGLOW", 9 );
704 0 : memcpy( msg+9, vote_account_pubkey, 32 );
705 0 : memcpy( msg+9+32, bls_pubkey, 48 );
706 :
707 : /* Verify */
708 0 : if( FD_UNLIKELY( fd_bls12_381_proof_of_possession_verify(
709 0 : msg,
710 0 : FD_VOTE_BLS_MSG_SZ,
711 0 : bls_proof,
712 0 : bls_pubkey
713 0 : )!=FD_BLS_SUCCESS ) ) {
714 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
715 0 : }
716 0 : return 0;
717 0 : }
718 : #undef FD_VOTE_BLS_MSG_SZ
719 :
720 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L716-L759 */
721 : static int
722 : authorize( fd_exec_instr_ctx_t * ctx,
723 : fd_borrowed_account_t * vote_account,
724 : int target_version,
725 : fd_pubkey_t const * authorized,
726 : fd_vote_authorize_t const * vote_authorize,
727 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
728 : ulong signers_cnt,
729 : fd_sol_sysvar_clock_t const * clock,
730 3 : int is_vote_authorize_with_bls_enabled ) {
731 3 : fd_vote_state_versioned_t * vote_state_versioned = &ctx->runtime->vote_program.authorize.vote_state;
732 :
733 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L724-L727 */
734 3 : int rc = get_vote_state_handler_checked( vote_account, target_version, 0, vote_state_versioned );
735 3 : if( FD_UNLIKELY( rc ) ) return rc;
736 :
737 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L729-L756 */
738 3 : switch( vote_authorize->discriminant ) {
739 :
740 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L730-L750 */
741 0 : case fd_vote_authorize_enum_voter: {
742 :
743 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L741-L743 */
744 0 : if( FD_UNLIKELY( is_vote_authorize_with_bls_enabled && fd_vsv_has_bls_pubkey( vote_state_versioned ) ) ) {
745 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
746 0 : }
747 :
748 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L731-L732 */
749 0 : int authorized_withdrawer_signer = !fd_vote_verify_authorized_signer(
750 0 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
751 0 : signers,
752 0 : signers_cnt
753 0 : );
754 :
755 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L737-L740 */
756 0 : ulong target_epoch;
757 0 : rc = fd_ulong_checked_add( clock->leader_schedule_epoch, 1UL, &target_epoch );
758 0 : if( FD_UNLIKELY( rc!=FD_EXECUTOR_INSTR_SUCCESS ) ) {
759 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
760 0 : }
761 :
762 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L747 */
763 0 : rc = fd_vsv_set_new_authorized_voter(
764 0 : ctx,
765 0 : vote_state_versioned,
766 0 : authorized,
767 0 : clock->epoch,
768 0 : target_epoch,
769 0 : NULL, /* no BLS pubkey */
770 0 : authorized_withdrawer_signer,
771 0 : signers,
772 0 : signers_cnt
773 0 : );
774 0 : if( FD_UNLIKELY( rc ) ) return rc;
775 0 : break;
776 0 : }
777 :
778 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L751-L756 */
779 3 : case fd_vote_authorize_enum_withdrawer: {
780 3 : rc = fd_vote_verify_authorized_signer(
781 3 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
782 3 : signers,
783 3 : signers_cnt
784 3 : );
785 3 : if( FD_UNLIKELY( rc ) ) return rc;
786 3 : fd_vsv_set_authorized_withdrawer( vote_state_versioned, authorized );
787 3 : break;
788 3 : }
789 :
790 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L770 */
791 0 : case fd_vote_authorize_enum_voter_with_bls: {
792 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L771-L773 */
793 0 : if( FD_UNLIKELY( !is_vote_authorize_with_bls_enabled ) ) {
794 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
795 0 : }
796 :
797 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L774-L775 */
798 0 : int authorized_withdrawer_signer = !fd_vote_verify_authorized_signer(
799 0 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
800 0 : signers,
801 0 : signers_cnt
802 0 : );
803 :
804 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L777-L782 */
805 0 : rc = fd_vote_verify_bls_proof_of_possession(
806 0 : ctx,
807 0 : vote_account->acc->pubkey,
808 0 : vote_authorize->voter_with_bls.bls_pubkey,
809 0 : vote_authorize->voter_with_bls.bls_proof_of_possession
810 0 : );
811 0 : if( FD_UNLIKELY( rc ) ) {
812 0 : return rc;
813 0 : }
814 :
815 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L787-L790 */
816 0 : ulong target_epoch;
817 0 : rc = fd_ulong_checked_add( clock->leader_schedule_epoch, 1UL, &target_epoch );
818 0 : if( FD_UNLIKELY( rc!=FD_EXECUTOR_INSTR_SUCCESS ) ) {
819 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
820 0 : }
821 :
822 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L784 */
823 0 : rc = fd_vsv_set_new_authorized_voter(
824 0 : ctx,
825 0 : vote_state_versioned,
826 0 : authorized,
827 0 : clock->epoch,
828 0 : target_epoch,
829 0 : vote_authorize->voter_with_bls.bls_pubkey,
830 0 : authorized_withdrawer_signer,
831 0 : signers,
832 0 : signers_cnt
833 0 : );
834 0 : if( FD_UNLIKELY( rc ) ) return rc;
835 :
836 0 : break;
837 0 : }
838 :
839 0 : default:
840 0 : FD_LOG_CRIT(( "unsupported vote_authorize discriminant: %u", vote_authorize->discriminant ));
841 3 : }
842 :
843 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L758 */
844 3 : return fd_vsv_set_vote_account_state( ctx, vote_account, vote_state_versioned );
845 3 : }
846 :
847 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L808-L835 */
848 : static int
849 : update_validator_identity( fd_exec_instr_ctx_t * ctx,
850 : int target_version,
851 : fd_borrowed_account_t * vote_account,
852 : fd_pubkey_t const * node_pubkey,
853 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
854 : ulong signers_cnt,
855 6 : int custom_commission_collector_enabled ) {
856 6 : fd_vote_state_versioned_t * vote_state_versioned = &ctx->runtime->vote_program.update_validator_identity.vote_state;
857 :
858 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L768-L771 */
859 6 : int rc = get_vote_state_handler_checked( vote_account, target_version, 0, vote_state_versioned );
860 6 : if( FD_UNLIKELY( rc ) ) return rc;
861 :
862 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L774 */
863 6 : rc = fd_vote_verify_authorized_signer(
864 6 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
865 6 : signers,
866 6 : signers_cnt
867 6 : );
868 6 : if( FD_UNLIKELY( rc ) ) return rc;
869 :
870 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L777 */
871 6 : rc = fd_vote_verify_authorized_signer( node_pubkey, signers, signers_cnt );
872 6 : if( FD_UNLIKELY( rc ) ) return rc;
873 :
874 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L826 */
875 6 : fd_vsv_set_node_pubkey( vote_state_versioned, node_pubkey );
876 :
877 : /* Before SIMD-0232, block_revenue_collector is always synced with node_pubkey.
878 : After SIMD-0232, the collector can be set independently.
879 : https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L828-L832 */
880 6 : if( !custom_commission_collector_enabled ) {
881 3 : fd_vsv_set_block_revenue_collector( vote_state_versioned, node_pubkey );
882 3 : }
883 :
884 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L834 */
885 6 : return fd_vsv_set_vote_account_state( ctx, vote_account, vote_state_versioned );
886 6 : }
887 :
888 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L971
889 : static int
890 0 : is_commission_update_allowed( ulong slot, fd_epoch_schedule_t const * epoch_schedule ) {
891 0 : if( FD_LIKELY( epoch_schedule->slots_per_epoch > 0UL ) ) {
892 0 : ulong relative_slot = fd_ulong_sat_sub( slot, epoch_schedule->first_normal_slot );
893 0 : relative_slot %= epoch_schedule->slots_per_epoch;
894 0 : return fd_ulong_sat_mul( relative_slot, 2 ) <= epoch_schedule->slots_per_epoch;
895 0 : } else {
896 0 : return 1;
897 0 : }
898 0 : }
899 :
900 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L838-L869 */
901 : static int
902 : update_commission( fd_exec_instr_ctx_t * ctx,
903 : int target_version,
904 : fd_borrowed_account_t * vote_account,
905 : uchar commission,
906 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
907 : ulong signers_cnt,
908 : fd_epoch_schedule_t const * epoch_schedule,
909 : fd_sol_sysvar_clock_t const * clock,
910 0 : int disable_commission_update_rule ) {
911 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L796-L799 */
912 0 : int rc = 0;
913 0 : int get_vsv_rc = get_vote_state_handler_checked(
914 0 : vote_account,
915 0 : target_version,
916 0 : false,
917 0 : &ctx->runtime->vote_program.update_commission.vote_state
918 0 : );
919 :
920 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L851-L855 */
921 0 : fd_vote_state_versioned_t * vote_state_versioned = NULL;
922 0 : int enforce_commission_update_rule = !disable_commission_update_rule;
923 0 : if( FD_LIKELY( get_vsv_rc==FD_EXECUTOR_INSTR_SUCCESS ) ) {
924 0 : vote_state_versioned = &ctx->runtime->vote_program.update_commission.vote_state;
925 0 : enforce_commission_update_rule = (!disable_commission_update_rule) && (commission>fd_vsv_get_commission( vote_state_versioned ));
926 0 : }
927 :
928 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L806-L808 */
929 0 : if( FD_UNLIKELY( enforce_commission_update_rule && !is_commission_update_allowed( clock->slot, epoch_schedule ) ) ) {
930 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_COMMISSION_UPDATE_TOO_LATE;
931 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
932 0 : }
933 :
934 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L810 */
935 0 : if( FD_UNLIKELY( get_vsv_rc ) ) return get_vsv_rc;
936 :
937 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L813 */
938 0 : rc = fd_vote_verify_authorized_signer(
939 0 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
940 0 : signers,
941 0 : signers_cnt
942 0 : );
943 0 : if( FD_UNLIKELY( rc ) ) return rc;
944 :
945 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L815 */
946 0 : fd_vsv_set_commission( vote_state_versioned, commission );
947 :
948 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L817 */
949 0 : return fd_vsv_set_vote_account_state( ctx, vote_account, vote_state_versioned );
950 0 : }
951 :
952 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.6/programs/vote/src/vote_state/mod.rs#L871-L906 */
953 : static int
954 : update_commission_bps( fd_exec_instr_ctx_t * ctx,
955 : fd_borrowed_account_t * vote_account,
956 : int target_version,
957 : fd_update_commission_bps_args_t const * args,
958 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
959 : ulong signers_cnt,
960 3 : int block_revenue_sharing ) {
961 3 : fd_vote_state_versioned_t * vote_state_versioned = &ctx->runtime->vote_program.update_commission_bps.vote_state;
962 :
963 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.6/programs/vote/src/vote_state/mod.rs#L882-L884 */
964 3 : if( FD_UNLIKELY( args->kind.discriminant==fd_commission_kind_enum_block_revenue && !block_revenue_sharing ) ) {
965 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
966 0 : }
967 :
968 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.6/programs/vote/src/vote_state/mod.rs#L886-L889 */
969 3 : int rc = get_vote_state_handler_checked( vote_account, target_version, false, vote_state_versioned );
970 3 : if( FD_UNLIKELY( rc ) ) return rc;
971 :
972 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.6/programs/vote/src/vote_state/mod.rs#L894 */
973 3 : rc = fd_vote_verify_authorized_signer(
974 3 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
975 3 : signers,
976 3 : signers_cnt
977 3 : );
978 3 : if( FD_UNLIKELY( rc ) ) return rc;
979 :
980 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.6/programs/vote/src/vote_state/mod.rs#L896-L903 */
981 3 : switch( args->kind.discriminant ) {
982 3 : case fd_commission_kind_enum_inflation_rewards: {
983 3 : fd_vsv_set_inflation_rewards_commission_bps( vote_state_versioned, args->commission_bps );
984 3 : break;
985 0 : }
986 0 : case fd_commission_kind_enum_block_revenue: {
987 0 : fd_vsv_set_block_revenue_commission_bps( vote_state_versioned, args->commission_bps );
988 0 : break;
989 0 : }
990 0 : default: {
991 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
992 0 : }
993 3 : }
994 :
995 3 : return fd_vsv_set_vote_account_state( ctx, vote_account, vote_state_versioned );
996 3 : }
997 :
998 : /* Updates the vote account's commission collector (SIMD-0232).
999 : collector_account==NULL means the collector is the vote account
1000 : itself, which is exempt from the collector constraints.
1001 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_state/mod.rs#L907-L935 */
1002 : static int
1003 : update_commission_collector( fd_exec_instr_ctx_t * ctx,
1004 : fd_borrowed_account_t * vote_account,
1005 : int target_version,
1006 : fd_borrowed_account_t const * collector_account,
1007 : fd_commission_kind_t const * kind,
1008 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1009 : ulong signers_cnt,
1010 66 : fd_rent_t const * rent ) {
1011 66 : fd_vote_state_versioned_t * vote_state_versioned = &ctx->runtime->vote_program.update_commission_collector.vote_state;
1012 :
1013 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_state/mod.rs#L916 */
1014 66 : int rc = get_vote_state_handler_checked( vote_account, target_version, 0, vote_state_versioned );
1015 66 : if( FD_UNLIKELY( rc ) ) return rc;
1016 :
1017 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_state/mod.rs#L918-L919 */
1018 51 : rc = fd_vote_verify_authorized_signer(
1019 51 : fd_vsv_get_authorized_withdrawer( vote_state_versioned ),
1020 51 : signers,
1021 51 : signers_cnt
1022 51 : );
1023 51 : if( FD_UNLIKELY( rc ) ) return rc;
1024 :
1025 : /* An external collector must be system program owned, rent-exempt,
1026 : and not reserved (checked via the writable flag).
1027 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_state/mod.rs#L866-L905 */
1028 45 : fd_pubkey_t const * new_collector_key;
1029 45 : if( !collector_account ) {
1030 12 : new_collector_key = (fd_pubkey_t const *)vote_account->acc->pubkey;
1031 33 : } else {
1032 33 : if( FD_UNLIKELY( !fd_pubkey_eq( fd_borrowed_account_get_owner( collector_account ), &fd_solana_system_program_id ) ) ) {
1033 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
1034 3 : }
1035 :
1036 30 : if( FD_UNLIKELY( fd_borrowed_account_get_lamports( collector_account ) <
1037 30 : fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( collector_account ) ) ) ) {
1038 3 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1039 3 : }
1040 :
1041 27 : if( FD_UNLIKELY( !fd_borrowed_account_is_writable( collector_account ) ) ) {
1042 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
1043 3 : }
1044 :
1045 24 : new_collector_key = (fd_pubkey_t const *)collector_account->acc->pubkey;
1046 24 : }
1047 :
1048 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_state/mod.rs#L923-L930 */
1049 36 : switch( kind->discriminant ) {
1050 21 : case fd_commission_kind_enum_inflation_rewards: {
1051 21 : fd_vsv_set_inflation_rewards_collector( vote_state_versioned, new_collector_key );
1052 21 : break;
1053 0 : }
1054 15 : case fd_commission_kind_enum_block_revenue: {
1055 15 : fd_vsv_set_block_revenue_collector( vote_state_versioned, new_collector_key );
1056 15 : break;
1057 0 : }
1058 0 : default: {
1059 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
1060 0 : }
1061 36 : }
1062 :
1063 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_state/mod.rs#L934 */
1064 36 : return fd_vsv_set_vote_account_state( ctx, vote_account, vote_state_versioned );
1065 36 : }
1066 :
1067 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L848C8-L903 */
1068 : static int
1069 : withdraw( fd_exec_instr_ctx_t * ctx,
1070 : fd_borrowed_account_t * vote_account,
1071 : int target_version,
1072 : ulong lamports,
1073 : ushort to_account_index,
1074 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1075 : ulong signers_cnt,
1076 : fd_rent_t const * rent_sysvar,
1077 : fd_sol_sysvar_clock_t const * clock,
1078 0 : int * deinitialized ) {
1079 0 : fd_vote_state_versioned_t * versioned = &ctx->runtime->vote_program.withdraw.vote_state;
1080 0 : *deinitialized = 0;
1081 :
1082 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L860-L863 */
1083 0 : int rc = get_vote_state_handler_checked( vote_account, target_version, 0, versioned );
1084 0 : if( FD_UNLIKELY( rc ) ) return rc;
1085 :
1086 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L865 */
1087 0 : rc = fd_vote_verify_authorized_signer(
1088 0 : fd_vsv_get_authorized_withdrawer( versioned ),
1089 0 : signers,
1090 0 : signers_cnt
1091 0 : );
1092 0 : if( FD_UNLIKELY( rc ) ) return rc;
1093 :
1094 : /* Always zero until SIMD-0123 is activated.
1095 : https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1136 */
1096 0 : ulong pending_delegator_rewards = fd_vsv_get_pending_delegator_rewards( versioned );
1097 :
1098 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L867-L870 */
1099 0 : ulong vote_account_lamports = fd_borrowed_account_get_lamports( vote_account );
1100 0 : if( FD_UNLIKELY( lamports>vote_account_lamports ) ) {
1101 0 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1102 0 : }
1103 0 : ulong remaining_balance = vote_account_lamports-lamports;
1104 :
1105 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L872-L896 */
1106 0 : if( FD_UNLIKELY( remaining_balance==0UL ) ) {
1107 : /* SIMD-0123: vote account cannot be closed if pending_delegator_rewards > 0.
1108 : https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1139-L1143 */
1109 0 : if( FD_UNLIKELY( pending_delegator_rewards > 0 ) ) {
1110 0 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1111 0 : }
1112 :
1113 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L873-L883 */
1114 0 : fd_vote_epoch_credits_t const * epoch_credits = fd_vsv_get_epoch_credits( versioned );
1115 0 : ulong last_epoch_with_credits;
1116 0 : int reject_active_vote_account_close = 0;
1117 0 : if( FD_LIKELY( !deq_fd_vote_epoch_credits_t_empty( epoch_credits ) ) ) {
1118 0 : ulong current_epoch = clock->epoch;
1119 0 : last_epoch_with_credits = deq_fd_vote_epoch_credits_t_peek_tail_const( epoch_credits )->epoch;
1120 0 : reject_active_vote_account_close = fd_ulong_sat_sub( current_epoch, last_epoch_with_credits )<2UL;
1121 0 : }
1122 :
1123 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L885-L890 */
1124 0 : if( FD_UNLIKELY( reject_active_vote_account_close ) ) {
1125 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_ACTIVE_VOTE_ACCOUNT_CLOSE;
1126 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1127 0 : } else {
1128 0 : rc = fd_vsv_deinitialize_vote_account_state(
1129 0 : ctx,
1130 0 : vote_account,
1131 0 : target_version
1132 0 : );
1133 0 : if( FD_UNLIKELY( rc ) ) return rc;
1134 0 : *deinitialized = 1;
1135 0 : }
1136 0 : } else {
1137 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L892-L895 */
1138 0 : ulong min_rent_exempt_balance = fd_rent_exempt_minimum_balance( rent_sysvar, fd_borrowed_account_get_data_len( vote_account ) );
1139 :
1140 : /* SIMD-0123: withdrawable balance when pending_delegator_rewards > 0
1141 : is lamports - pending_delegator_rewards - rent_exempt_minimum.
1142 : https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1164-L1169 */
1143 0 : ulong min_balance;
1144 0 : if( FD_UNLIKELY( fd_ulong_checked_add( min_rent_exempt_balance, pending_delegator_rewards, &min_balance ) ) ) {
1145 0 : return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
1146 0 : }
1147 :
1148 0 : if( FD_UNLIKELY( remaining_balance<min_balance ) ) {
1149 0 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1150 0 : }
1151 0 : }
1152 :
1153 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L898 */
1154 0 : rc = fd_borrowed_account_checked_sub_lamports( vote_account, lamports );
1155 0 : if( FD_UNLIKELY( rc ) ) return rc;
1156 :
1157 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L899 */
1158 0 : fd_borrowed_account_drop( vote_account );
1159 :
1160 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L900 */
1161 0 : fd_guarded_borrowed_account_t to = {0};
1162 0 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, to_account_index, &to );
1163 :
1164 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L901 */
1165 0 : rc = fd_borrowed_account_checked_add_lamports( &to, lamports );
1166 0 : if( FD_UNLIKELY( rc ) ) return rc;
1167 :
1168 0 : return FD_EXECUTOR_INSTR_SUCCESS;
1169 0 : }
1170 :
1171 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L638-L651 */
1172 : static int
1173 : process_vote_unfiltered( fd_exec_instr_ctx_t * ctx,
1174 : fd_vote_state_versioned_t * versioned,
1175 : ulong * vote_slots,
1176 : fd_vote_t const * vote,
1177 : fd_slot_hashes_t const * slot_hashes,
1178 : ulong epoch,
1179 0 : ulong current_slot ) {
1180 0 : int rc;
1181 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L770
1182 0 : rc = check_slots_are_valid( ctx, versioned, vote_slots, &vote->hash, slot_hashes );
1183 0 : if( FD_UNLIKELY( rc ) ) return rc;
1184 0 : for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote_slots );
1185 0 : !deq_ulong_iter_done( vote_slots, iter );
1186 0 : iter = deq_ulong_iter_next( vote_slots, iter ) ) {
1187 0 : ulong * ele = deq_ulong_iter_ele( vote_slots, iter );
1188 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L772
1189 0 : fd_vsv_process_next_vote_slot( versioned, *ele, epoch, current_slot );
1190 0 : }
1191 0 : return 0;
1192 0 : }
1193 :
1194 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L783
1195 : static int
1196 : process_vote( fd_exec_instr_ctx_t * ctx,
1197 : fd_vote_state_versioned_t * versioned,
1198 : fd_vote_t const * vote,
1199 : fd_slot_hashes_t const * slot_hashes,
1200 : ulong epoch,
1201 0 : ulong current_slot ) {
1202 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L792
1203 0 : if( FD_UNLIKELY( deq_ulong_empty( vote->slots ) ) ) {
1204 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
1205 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1206 0 : }
1207 :
1208 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L795
1209 0 : ulong earliest_slot_in_history = 0;
1210 0 : if( FD_UNLIKELY( !!slot_hashes->cnt ) ) {
1211 0 : earliest_slot_in_history = slot_hashes->elems[ slot_hashes->cnt-1UL ].slot;
1212 0 : }
1213 :
1214 : /* We know that the size of the vote_slots is bounded by the number of
1215 : slots that can fit inside of an instruction. Because the
1216 : instructions are deserialized with
1217 : limited_deserialize(data, PACKET_DATA_SIZE), we can use
1218 : FD_TXN_MTU_V0 as a bound on the size of the instruction. If this
1219 : instruction is filled only with a vote slot deque, we get
1220 : (1232/8) == 154 slots.
1221 : The footprint of a deque is as follows:
1222 : fd_ulong_align_up( fd_ulong_align_up( 32UL, alignof(DEQUE_T) ) + sizeof(DEQUE_T)*max, alignof(DEQUE_(private_t)) );
1223 : So, the footprint in our case is:
1224 : fd_ulong_align_up( fd_ulong_align_up( 32UL, alignof(ulong) ) + sizeof(ulong)*154, alignof(DEQUE_(private_t)) );
1225 : Which is equal to
1226 : fd_ulong_align_up( 32UL + 154 * 8UL, 8UL ) = 1264UL; */
1227 0 : #define VOTE_SLOTS_MAX (FD_TXN_MTU_V0/sizeof(ulong))
1228 0 : #define VOTE_SLOTS_DEQUE_FOOTPRINT (1264UL )
1229 0 : #define VOTE_SLOTS_DEQUE_ALIGN (8UL)
1230 0 : FD_TEST( deq_ulong_footprint( VOTE_SLOTS_MAX ) == VOTE_SLOTS_DEQUE_FOOTPRINT );
1231 0 : FD_TEST( deq_ulong_align() == 8UL );
1232 0 : FD_TEST( deq_ulong_cnt( vote->slots ) <= VOTE_SLOTS_MAX );
1233 0 : uchar * vote_slots_mem[ VOTE_SLOTS_DEQUE_FOOTPRINT ] __attribute__((aligned(VOTE_SLOTS_DEQUE_ALIGN)));
1234 :
1235 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L796
1236 0 : ulong * vote_slots = deq_ulong_join( deq_ulong_new( vote_slots_mem, deq_ulong_cnt( vote->slots ) ) );
1237 0 : for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote->slots );
1238 0 : !deq_ulong_iter_done( vote->slots, iter );
1239 0 : iter = deq_ulong_iter_next( vote->slots, iter ) ) {
1240 0 : ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
1241 0 : if( FD_UNLIKELY( *ele >= earliest_slot_in_history ) ) {
1242 0 : vote_slots = deq_ulong_push_tail_wrap( vote_slots, *ele );
1243 0 : }
1244 0 : }
1245 :
1246 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L802
1247 0 : if( FD_UNLIKELY( deq_ulong_cnt( vote_slots ) == 0 ) ) {
1248 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_VOTES_TOO_OLD_ALL_FILTERED;
1249 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1250 0 : }
1251 :
1252 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L805
1253 0 : return process_vote_unfiltered(
1254 0 : ctx,
1255 0 : versioned,
1256 0 : vote_slots,
1257 0 : vote,
1258 0 : slot_hashes,
1259 0 : epoch,
1260 0 : current_slot
1261 0 : );
1262 0 : }
1263 :
1264 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L905-L926 */
1265 : static int
1266 : initialize_account( fd_exec_instr_ctx_t * ctx,
1267 : fd_borrowed_account_t * vote_account,
1268 : int target_version,
1269 : fd_vote_init_t * vote_init,
1270 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1271 : ulong signers_cnt,
1272 24 : fd_sol_sysvar_clock_t const * clock ) {
1273 24 : int rc;
1274 24 : fd_vote_state_versioned_t * versioned = &ctx->runtime->vote_program.init_account.vote_state;
1275 :
1276 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L915 */
1277 24 : rc = check_vote_account_length( vote_account, target_version );
1278 24 : if( FD_UNLIKELY( rc ) ) return rc;
1279 :
1280 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L916 */
1281 24 : rc = fd_vsv_get_state( vote_account->acc, versioned );
1282 24 : if( FD_UNLIKELY( rc ) ) return rc;
1283 :
1284 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L918-L920 */
1285 24 : if( FD_UNLIKELY( !fd_vsv_is_uninitialized( versioned ) ) ) {
1286 0 : return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
1287 0 : }
1288 :
1289 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L923 */
1290 24 : rc = fd_vote_verify_authorized_signer( &vote_init->node_pubkey, signers, signers_cnt );
1291 24 : if( FD_UNLIKELY( rc ) ) {
1292 0 : return rc;
1293 0 : }
1294 :
1295 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L925 */
1296 24 : return init_vote_account_state( ctx, vote_account, versioned, target_version, vote_init, clock );
1297 24 : }
1298 :
1299 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1182-L1216
1300 : Note: this is very similar to initialize_account() but also does verify_bls_proof_of_possession() */
1301 : static int
1302 : initialize_account_v2( fd_exec_instr_ctx_t * ctx,
1303 : fd_borrowed_account_t * vote_account,
1304 : int target_version,
1305 : fd_vote_init_v2_t * vote_init_v2,
1306 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1307 : ulong signers_cnt,
1308 0 : fd_sol_sysvar_clock_t const * clock ) {
1309 0 : int rc;
1310 0 : fd_vote_state_versioned_t * versioned = &ctx->runtime->vote_program.init_account.vote_state;
1311 :
1312 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1198 */
1313 0 : rc = check_vote_account_length( vote_account, target_version );
1314 0 : if( FD_UNLIKELY( rc ) ) return rc;
1315 :
1316 0 : rc = fd_vsv_get_state( vote_account->acc, versioned );
1317 0 : if( FD_UNLIKELY( rc ) ) return rc;
1318 :
1319 0 : if( FD_UNLIKELY( !fd_vsv_is_uninitialized( versioned ) ) ) {
1320 0 : return FD_EXECUTOR_INSTR_ERR_ACC_ALREADY_INITIALIZED;
1321 0 : }
1322 :
1323 0 : rc = fd_vote_verify_authorized_signer( &vote_init_v2->node_pubkey, signers, signers_cnt );
1324 0 : if( FD_UNLIKELY( rc ) ) {
1325 0 : return rc;
1326 0 : }
1327 :
1328 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1208-L1213 */
1329 0 : rc = fd_vote_verify_bls_proof_of_possession(
1330 0 : ctx,
1331 0 : vote_account->acc->pubkey,
1332 0 : vote_init_v2->authorized_voter_bls_pubkey,
1333 0 : vote_init_v2->authorized_voter_bls_proof_of_possession
1334 0 : );
1335 0 : if( FD_UNLIKELY( rc ) ) {
1336 0 : return rc;
1337 0 : }
1338 :
1339 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_state/mod.rs#L1215 */
1340 0 : return init_vote_account_state_v2( ctx, vote_account, versioned, target_version, vote_init_v2, clock );
1341 0 : }
1342 :
1343 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L928-L953 */
1344 : static int
1345 : process_vote_with_account( fd_exec_instr_ctx_t * ctx,
1346 : fd_borrowed_account_t * vote_account,
1347 : int target_version,
1348 : fd_slot_hashes_t const * slot_hashes,
1349 : fd_sol_sysvar_clock_t const * clock,
1350 : fd_vote_t * vote,
1351 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1352 0 : ulong signers_cnt ) {
1353 0 : fd_vote_state_versioned_t * versioned = &ctx->runtime->vote_program.process_vote.vote_state;
1354 :
1355 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L936-L939 */
1356 0 : int rc = get_vote_state_handler_checked( vote_account, target_version, 1, versioned );
1357 0 : if( FD_UNLIKELY( rc ) ) return rc;
1358 :
1359 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L941 */
1360 0 : fd_pubkey_t * authorized_voter = NULL;
1361 0 : rc = fd_authorized_voters_get_and_update_authorized_voter( versioned, clock->epoch, &authorized_voter );
1362 0 : if( FD_UNLIKELY( rc ) ) return rc;
1363 :
1364 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L942 */
1365 0 : rc = fd_vote_verify_authorized_signer( authorized_voter, signers, signers_cnt );
1366 0 : if( FD_UNLIKELY( rc ) ) return rc;
1367 :
1368 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L944 */
1369 0 : rc = process_vote( ctx, versioned, vote, slot_hashes, clock->epoch, clock->slot );
1370 0 : if( FD_UNLIKELY( rc ) ) return rc;
1371 :
1372 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L945-L951 */
1373 0 : if( FD_LIKELY( vote->has_timestamp ) ) {
1374 : /* Calling max() on an empty iterator returns None */
1375 0 : if( FD_UNLIKELY( deq_ulong_cnt( vote->slots )==0 ) ) {
1376 0 : ctx->txn_out->err.custom_err = FD_VOTE_ERR_EMPTY_SLOTS;
1377 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1378 0 : }
1379 :
1380 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L948 */
1381 0 : ulong max = 0UL;
1382 0 : for( deq_ulong_iter_t iter = deq_ulong_iter_init( vote->slots );
1383 0 : !deq_ulong_iter_done( vote->slots, iter );
1384 0 : iter = deq_ulong_iter_next( vote->slots, iter ) ) {
1385 0 : ulong * ele = deq_ulong_iter_ele( vote->slots, iter );
1386 0 : max = fd_ulong_max( max, *ele );
1387 0 : }
1388 :
1389 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L950 */
1390 0 : rc = fd_vsv_process_timestamp( ctx, versioned, max, vote->timestamp );
1391 0 : if( FD_UNLIKELY( rc ) ) return rc;
1392 0 : }
1393 :
1394 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L952 */
1395 0 : return fd_vsv_set_vote_account_state( ctx, vote_account, versioned );
1396 0 : }
1397 :
1398 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1156
1399 : static int
1400 : do_process_vote_state_update( fd_exec_instr_ctx_t * ctx,
1401 : fd_vote_state_versioned_t * versioned,
1402 : fd_slot_hashes_t const * slot_hashes,
1403 : ulong epoch,
1404 : ulong slot,
1405 0 : fd_vote_state_update_t * vote_state_update ) {
1406 0 : int rc;
1407 :
1408 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1164
1409 0 : rc = check_and_filter_proposed_vote_state(
1410 0 : ctx,
1411 0 : versioned,
1412 0 : vote_state_update->lockouts,
1413 0 : &vote_state_update->has_root,
1414 0 : &vote_state_update->root,
1415 0 : &vote_state_update->hash,
1416 0 : slot_hashes
1417 0 : );
1418 0 : if( FD_UNLIKELY( rc ) ) return rc;
1419 :
1420 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1177
1421 0 : fd_landed_vote_t * landed_votes = deq_fd_landed_vote_t_join( deq_fd_landed_vote_t_new( ctx->runtime->vote_program.process_vote.vs_update_landed_votes_mem, deq_fd_vote_lockout_t_cnt( vote_state_update->lockouts ) ) );
1422 0 : for( deq_fd_vote_lockout_t_iter_t iter =
1423 0 : deq_fd_vote_lockout_t_iter_init( vote_state_update->lockouts );
1424 0 : !deq_fd_vote_lockout_t_iter_done( vote_state_update->lockouts, iter );
1425 0 : iter = deq_fd_vote_lockout_t_iter_next( vote_state_update->lockouts, iter ) ) {
1426 0 : fd_vote_lockout_t * lockout =
1427 0 : deq_fd_vote_lockout_t_iter_ele( vote_state_update->lockouts, iter );
1428 0 : deq_fd_landed_vote_t_push_tail_wrap( landed_votes,
1429 0 : ( fd_landed_vote_t ){ .latency = 0, .lockout = *lockout } );
1430 0 : }
1431 :
1432 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_state/mod.rs#L1171
1433 0 : return process_new_vote_state(
1434 0 : ctx,
1435 0 : versioned,
1436 0 : landed_votes,
1437 0 : vote_state_update->has_root,
1438 0 : vote_state_update->root,
1439 0 : vote_state_update->has_timestamp,
1440 0 : vote_state_update->timestamp,
1441 0 : epoch,
1442 0 : slot
1443 0 : );
1444 0 : }
1445 :
1446 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L955-L979 */
1447 : static int
1448 : process_vote_state_update( fd_exec_instr_ctx_t * ctx,
1449 : fd_borrowed_account_t * vote_account,
1450 : int target_version,
1451 : fd_slot_hashes_t const * slot_hashes,
1452 : fd_sol_sysvar_clock_t const * clock,
1453 : fd_vote_state_update_t * vote_state_update,
1454 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1455 0 : ulong signers_cnt ) {
1456 0 : fd_vote_state_versioned_t * versioned = &ctx->runtime->vote_program.process_vote.vote_state;
1457 :
1458 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L963-L966 */
1459 0 : int rc = get_vote_state_handler_checked( vote_account, target_version, 1, versioned );
1460 0 : if( FD_UNLIKELY( rc ) ) return rc;
1461 :
1462 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L968 */
1463 0 : fd_pubkey_t * authorized_voter = NULL;
1464 0 : rc = fd_authorized_voters_get_and_update_authorized_voter( versioned, clock->epoch, &authorized_voter );
1465 0 : if( FD_UNLIKELY( rc ) ) return rc;
1466 :
1467 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L969 */
1468 0 : rc = fd_vote_verify_authorized_signer( authorized_voter, signers, signers_cnt );
1469 0 : if( FD_UNLIKELY( rc ) ) return rc;
1470 :
1471 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L971-L977 */
1472 0 : rc = do_process_vote_state_update(
1473 0 : ctx,
1474 0 : versioned,
1475 0 : slot_hashes,
1476 0 : clock->epoch,
1477 0 : clock->slot,
1478 0 : vote_state_update
1479 0 : );
1480 0 : if( FD_UNLIKELY( rc ) ) {
1481 0 : return rc;
1482 0 : }
1483 :
1484 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L978 */
1485 0 : return fd_vsv_set_vote_account_state( ctx, vote_account, versioned );
1486 0 : }
1487 :
1488 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1035-L1061 */
1489 : static int
1490 : do_process_tower_sync( fd_exec_instr_ctx_t * ctx,
1491 : fd_vote_state_versioned_t * versioned,
1492 : fd_slot_hashes_t const * slot_hashes,
1493 : ulong epoch,
1494 : ulong slot,
1495 0 : fd_tower_sync_t * tower_sync ) {
1496 :
1497 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1042-L1048 */
1498 0 : int rc = check_and_filter_proposed_vote_state(
1499 0 : ctx,
1500 0 : versioned,
1501 0 : tower_sync->lockouts,
1502 0 : &tower_sync->has_root,
1503 0 : &tower_sync->root,
1504 0 : &tower_sync->hash,
1505 0 : slot_hashes
1506 0 : );
1507 0 : if( FD_UNLIKELY( rc ) ) return rc;
1508 :
1509 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1049-L1060 */
1510 0 : return process_new_vote_state(
1511 0 : ctx,
1512 0 : versioned,
1513 0 : fd_vote_lockout_landed_votes_from_lockouts( tower_sync->lockouts, ctx->runtime->vote_program.tower_sync.tower_sync_landed_votes_mem ),
1514 0 : tower_sync->has_root,
1515 0 : tower_sync->root,
1516 0 : tower_sync->has_timestamp,
1517 0 : tower_sync->timestamp,
1518 0 : epoch,
1519 0 : slot
1520 0 : );
1521 0 : }
1522 :
1523 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1009-L1033 */
1524 : static int
1525 : process_tower_sync( fd_exec_instr_ctx_t * ctx,
1526 : fd_borrowed_account_t * vote_account,
1527 : int target_version,
1528 : fd_slot_hashes_t const * slot_hashes,
1529 : fd_sol_sysvar_clock_t const * clock,
1530 : fd_tower_sync_t * tower_sync,
1531 : fd_pubkey_t const * signers[static FD_INSTR_SIGNERS_MAX],
1532 0 : ulong signers_cnt ) {
1533 0 : fd_vote_state_versioned_t * versioned = &ctx->runtime->vote_program.tower_sync.vote_state;
1534 :
1535 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1017-L1020 */
1536 0 : int rc = get_vote_state_handler_checked( vote_account, target_version, 1, versioned );
1537 0 : if( FD_UNLIKELY( rc ) ) return rc;
1538 :
1539 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1022 */
1540 0 : fd_pubkey_t * authorized_voter = NULL;
1541 0 : rc = fd_authorized_voters_get_and_update_authorized_voter( versioned, clock->epoch, &authorized_voter );
1542 0 : if( FD_UNLIKELY( rc ) ) return rc;
1543 :
1544 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1023 */
1545 0 : rc = fd_vote_verify_authorized_signer( authorized_voter, signers, signers_cnt );
1546 0 : if( FD_UNLIKELY( rc ) ) return rc;
1547 :
1548 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1025-L1031 */
1549 0 : rc = do_process_tower_sync(
1550 0 : ctx,
1551 0 : versioned,
1552 0 : slot_hashes,
1553 0 : clock->epoch,
1554 0 : clock->slot,
1555 0 : tower_sync
1556 0 : );
1557 0 : if( FD_UNLIKELY( rc ) ) return rc;
1558 :
1559 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_state/mod.rs#L1032 */
1560 0 : return fd_vsv_set_vote_account_state( ctx, vote_account, versioned );
1561 0 : }
1562 :
1563 : /**********************************************************************/
1564 : /* FD-only encoders / decoders (doesn't map directly to Labs impl) */
1565 : /**********************************************************************/
1566 :
1567 : int
1568 : fd_vote_decode_compact_update( fd_compact_vote_state_update_t * compact_update,
1569 : fd_vote_state_update_t * vote_update,
1570 0 : fd_exec_instr_ctx_t const * ctx ) {
1571 : // Taken from:
1572 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/state/mod.rs#L954
1573 0 : if( compact_update->root != ULONG_MAX ) {
1574 0 : vote_update->has_root = 1;
1575 0 : vote_update->root = compact_update->root;
1576 0 : } else {
1577 0 : vote_update->has_root = 0;
1578 0 : vote_update->root = ULONG_MAX;
1579 0 : }
1580 :
1581 0 : ulong lockouts_len = compact_update->lockouts_len;
1582 0 : ulong lockouts_max = fd_ulong_max( lockouts_len, MAX_LOCKOUT_HISTORY );
1583 :
1584 0 : vote_update->lockouts = deq_fd_vote_lockout_t_join( deq_fd_vote_lockout_t_new( ctx->runtime->vote_program.process_vote.compact_vs_lockout_mem, lockouts_max ) );
1585 0 : ulong slot = fd_ulong_if( vote_update->has_root, vote_update->root, 0 );
1586 :
1587 0 : for( ulong i=0; i < lockouts_len; ++i ) {
1588 0 : fd_vote_lockout_t * elem = deq_fd_vote_lockout_t_push_tail_nocopy( vote_update->lockouts );
1589 0 : fd_lockout_offset_t * lock_offset = &compact_update->lockouts[i];
1590 :
1591 0 : ulong next_slot;
1592 0 : if( FD_UNLIKELY( __builtin_uaddl_overflow( slot, lock_offset->offset, &next_slot ) ) ) {
1593 0 : return 0;
1594 0 : }
1595 :
1596 0 : elem->slot = slot = next_slot;
1597 0 : elem->confirmation_count = (uint)lock_offset->confirmation_count;
1598 0 : }
1599 :
1600 0 : vote_update->hash = compact_update->hash;
1601 0 : vote_update->has_timestamp = compact_update->has_timestamp;
1602 0 : vote_update->timestamp = compact_update->timestamp;
1603 :
1604 0 : return 1;
1605 0 : }
1606 :
1607 : /**********************************************************************/
1608 : /* mod vote_processor */
1609 : /**********************************************************************/
1610 :
1611 : /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L21-L51 */
1612 : static int
1613 : process_authorize_with_seed_instruction( /* invoke_context */
1614 : fd_exec_instr_ctx_t * ctx,
1615 : int target_version,
1616 : fd_borrowed_account_t * vote_account,
1617 : fd_pubkey_t const * new_authority,
1618 : fd_vote_authorize_t const * authorization_type,
1619 : fd_pubkey_t const * current_authority_derived_key_owner,
1620 : uchar const * current_authority_derived_key_seed,
1621 : ulong current_authority_derived_key_seed_len,
1622 0 : int is_vote_authorize_with_bls_enabled ) {
1623 0 : int rc = 0;
1624 :
1625 : /* https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L31 */
1626 0 : rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id );
1627 0 : if( FD_UNLIKELY( rc ) ) return rc;
1628 :
1629 0 : fd_sol_sysvar_clock_t clock_;
1630 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
1631 0 : if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1632 :
1633 0 : fd_pubkey_t * expected_authority_keys[FD_INSTR_SIGNERS_MAX] = { 0 };
1634 0 : ulong expected_authority_keys_cnt = 0UL;
1635 0 : fd_pubkey_t single_signer = { 0 };
1636 :
1637 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L30-L42 */
1638 0 : if( fd_instr_acc_is_signer_idx( ctx->instr, 2, &rc ) ) {
1639 :
1640 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L31 */
1641 0 : fd_pubkey_t const * base_pubkey = NULL;
1642 0 : rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 2UL, &base_pubkey );
1643 0 : if( FD_UNLIKELY( rc ) ) return rc;
1644 :
1645 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L34-L40 */
1646 0 : expected_authority_keys[0] = &single_signer;
1647 0 : rc = fd_pubkey_create_with_seed( ctx,
1648 0 : base_pubkey->uc,
1649 0 : (char const *)current_authority_derived_key_seed,
1650 0 : current_authority_derived_key_seed_len,
1651 0 : current_authority_derived_key_owner->uc,
1652 0 : /* insert */ expected_authority_keys[0]->uc );
1653 0 : if( FD_UNLIKELY( rc ) ) return rc;
1654 0 : expected_authority_keys_cnt = 1UL;
1655 0 : }
1656 :
1657 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L43-L50 */
1658 0 : return authorize(
1659 0 : ctx,
1660 0 : vote_account,
1661 0 : target_version,
1662 0 : new_authority,
1663 0 : authorization_type,
1664 0 : (fd_pubkey_t const **)expected_authority_keys,
1665 0 : expected_authority_keys_cnt,
1666 0 : clock,
1667 0 : is_vote_authorize_with_bls_enabled
1668 0 : );
1669 0 : }
1670 :
1671 : /**********************************************************************/
1672 : /* Entry point for the Vote Program */
1673 : /**********************************************************************/
1674 :
1675 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L57
1676 : int
1677 114 : fd_vote_program_execute( fd_exec_instr_ctx_t * ctx ) {
1678 : /* FD-specific init */
1679 114 : int rc = FD_EXECUTOR_INSTR_SUCCESS;
1680 :
1681 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L57
1682 114 : FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS );
1683 :
1684 : /* https://github.com/anza-xyz/agave/blob/v3.1.1/programs/vote/src/vote_processor.rs#L64-L67 */
1685 114 : fd_guarded_borrowed_account_t me = {0};
1686 114 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0, &me );
1687 114 : if( FD_UNLIKELY( !fd_pubkey_eq( fd_borrowed_account_get_owner( &me ), &fd_solana_vote_program_id ) ) ) {
1688 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
1689 0 : }
1690 :
1691 : /* https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_processor.rs#L118-L119 */
1692 114 : int target_version = VOTE_STATE_TARGET_VERSION_V4;
1693 :
1694 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L69
1695 114 : fd_pubkey_t const * signers[FD_INSTR_SIGNERS_MAX] = { 0 };
1696 114 : ulong signers_cnt = 0UL;
1697 114 : fd_exec_instr_ctx_get_signers( ctx, signers, &signers_cnt );
1698 :
1699 : /* Some of these features are not implemented yet. As such, they are
1700 : not in feature_map.json.
1701 :
1702 : TODO: don't hardcode these when the features are implemented. */
1703 114 : int bls_pubkey_management_in_vote_account = FD_FEATURE_ACTIVE_BANK( ctx->bank, bls_pubkey_management_in_vote_account );
1704 114 : int delay_commission_updates = FD_FEATURE_ACTIVE_BANK( ctx->bank, delay_commission_updates );
1705 114 : int commission_rate_in_basis_points = FD_FEATURE_ACTIVE_BANK( ctx->bank, commission_rate_in_basis_points );
1706 114 : int custom_commission_collector = FD_FEATURE_ACTIVE_BANK( ctx->bank, custom_commission_collector );
1707 114 : int block_revenue_sharing = 0;
1708 114 : int vote_account_initialize_v2 = 0;
1709 :
1710 : /* https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_processor.rs#L72-L76 */
1711 114 : int is_vote_authorize_with_bls_enabled = bls_pubkey_management_in_vote_account;
1712 :
1713 : /* https://github.com/anza-xyz/agave/blob/v4.1.0-alpha.0/programs/vote/src/vote_processor.rs#L63-L70 */
1714 114 : int is_init_account_v2_enabled =
1715 114 : bls_pubkey_management_in_vote_account &&
1716 114 : commission_rate_in_basis_points &&
1717 114 : custom_commission_collector &&
1718 114 : block_revenue_sharing &&
1719 114 : vote_account_initialize_v2;
1720 :
1721 114 : fd_vote_instruction_t instruction[1];
1722 114 : if( FD_UNLIKELY( !fd_vote_instruction_deserialize( instruction, ctx->instr->data, ctx->instr->data_sz ) ) ) {
1723 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
1724 0 : }
1725 :
1726 : /* PLEASE PRESERVE SWITCH-CASE ORDERING TO MIRROR LABS IMPL:
1727 : */
1728 114 : switch( instruction->discriminant ) {
1729 :
1730 : /* InitializeAccount
1731 : *
1732 : * Instruction:
1733 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L32
1734 : *
1735 : * Processor:
1736 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L71
1737 : */
1738 24 : case fd_vote_instruction_enum_initialize_account: {
1739 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L72
1740 24 : rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id );
1741 24 : if( FD_UNLIKELY( rc ) ) return rc;
1742 24 : fd_rent_t rent_;
1743 24 : fd_rent_t const * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
1744 24 : if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1745 :
1746 24 : if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &me ) <
1747 24 : fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &me ) ) ) )
1748 0 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1749 :
1750 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L76
1751 24 : rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id );
1752 24 : if( FD_UNLIKELY( rc ) ) return rc;
1753 24 : fd_sol_sysvar_clock_t clock_;
1754 24 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
1755 24 : if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1756 :
1757 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L78
1758 24 : rc = initialize_account( ctx, &me, target_version, &instruction->initialize_account, signers, signers_cnt, clock );
1759 :
1760 24 : if( FD_LIKELY( !rc ) ) {
1761 24 : ctx->txn_out->accounts.new_vote[ ctx->instr->accounts[0].index_in_transaction ] = 1;
1762 24 : ctx->txn_out->accounts.rm_vote[ ctx->instr->accounts[0].index_in_transaction ] = 0;
1763 24 : }
1764 :
1765 24 : break;
1766 24 : }
1767 :
1768 : /* Authorize
1769 : *
1770 : * Instruction:
1771 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L40
1772 : *
1773 : * Processor:
1774 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L86
1775 : *
1776 : * Notes:
1777 : * - Up to two signers: the vote authority and the authorized withdrawer.
1778 : */
1779 3 : case fd_vote_instruction_enum_authorize: {
1780 3 : fd_pubkey_t const * voter_pubkey = &instruction->authorize.pubkey;
1781 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L87
1782 3 : rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id );
1783 3 : if( FD_UNLIKELY( rc ) ) return rc;
1784 3 : fd_sol_sysvar_clock_t clock_;
1785 3 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
1786 3 : if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1787 :
1788 3 : rc = authorize( ctx, &me, target_version, voter_pubkey, &instruction->authorize.vote_authorize, signers, signers_cnt, clock, is_vote_authorize_with_bls_enabled );
1789 :
1790 3 : break;
1791 3 : }
1792 :
1793 : /* AuthorizeWithSeed
1794 : *
1795 : * Instruction:
1796 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L117
1797 : *
1798 : * Processor:
1799 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L98
1800 : */
1801 0 : case fd_vote_instruction_enum_authorize_with_seed: {
1802 0 : fd_vote_authorize_with_seed_args_t * args = &instruction->authorize_with_seed;
1803 :
1804 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L99
1805 0 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 3 ) ) {
1806 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
1807 0 : break;
1808 0 : }
1809 :
1810 0 : rc = process_authorize_with_seed_instruction(
1811 0 : ctx,
1812 0 : target_version,
1813 0 : &me,
1814 0 : &args->new_authority,
1815 0 : &args->authorization_type,
1816 0 : &args->current_authority_derived_key_owner,
1817 0 : args->current_authority_derived_key_seed,
1818 0 : args->current_authority_derived_key_seed_len,
1819 0 : is_vote_authorize_with_bls_enabled
1820 0 : );
1821 :
1822 0 : break;
1823 0 : }
1824 :
1825 : /* AuthorizeCheckedWithSeed
1826 : *
1827 : * Instruction:
1828 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L131
1829 : *
1830 : * Processor:
1831 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L111
1832 : */
1833 0 : case fd_vote_instruction_enum_authorize_checked_with_seed: {
1834 0 : fd_vote_authorize_checked_with_seed_args_t const * args = &instruction->authorize_checked_with_seed;
1835 :
1836 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L112
1837 0 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 4 ) ) {
1838 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
1839 0 : break;
1840 0 : }
1841 :
1842 : // https://github.com/anza-xyz/agave/blob/v2.1.14/programs/vote/src/vote_processor.rs#L99-L100
1843 0 : fd_pubkey_t const * new_authority = NULL;
1844 0 : rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 3UL, &new_authority );
1845 0 : if( FD_UNLIKELY( rc ) ) return rc;
1846 :
1847 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L116
1848 0 : if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3, &rc ) ) ) {
1849 : /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
1850 0 : if( FD_UNLIKELY( !!rc ) ) break;
1851 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L117
1852 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
1853 0 : break;
1854 0 : }
1855 :
1856 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L119
1857 0 : rc = process_authorize_with_seed_instruction(
1858 0 : ctx,
1859 0 : target_version,
1860 0 : &me,
1861 0 : new_authority,
1862 0 : &args->authorization_type,
1863 0 : &args->current_authority_derived_key_owner,
1864 0 : args->current_authority_derived_key_seed,
1865 0 : args->current_authority_derived_key_seed_len,
1866 0 : is_vote_authorize_with_bls_enabled );
1867 :
1868 0 : break;
1869 0 : }
1870 :
1871 : /* UpdateValidatorIdentity
1872 : *
1873 : * Instruction:
1874 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L65
1875 : *
1876 : * Processor:
1877 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L130
1878 : */
1879 6 : case fd_vote_instruction_enum_update_validator_identity: {
1880 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L131
1881 6 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) ) {
1882 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
1883 0 : break;
1884 0 : }
1885 :
1886 : // https://github.com/anza-xyz/agave/blob/v2.1.14/programs/vote/src/vote_processor.rs#L118-L120
1887 6 : fd_pubkey_t const * node_pubkey = NULL;
1888 6 : rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 1UL, &node_pubkey );
1889 6 : if( FD_UNLIKELY( rc ) ) return rc;
1890 :
1891 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L135
1892 6 : rc = update_validator_identity( ctx, target_version, &me, node_pubkey, signers, signers_cnt, custom_commission_collector );
1893 :
1894 6 : break;
1895 6 : }
1896 :
1897 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L142
1898 0 : case fd_vote_instruction_enum_update_commission: {
1899 :
1900 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L149
1901 0 : fd_epoch_schedule_t epoch_schedule_;
1902 0 : fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_cache_epoch_schedule_read( ctx->sysvar_cache, &epoch_schedule_ );
1903 0 : if( FD_UNLIKELY( !epoch_schedule ) ) {
1904 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1905 0 : }
1906 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L150
1907 :
1908 0 : fd_sol_sysvar_clock_t clock_;
1909 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
1910 0 : if( FD_UNLIKELY( !clock ) ) {
1911 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1912 0 : }
1913 :
1914 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L145
1915 0 : rc = update_commission(
1916 0 : ctx,
1917 0 : target_version,
1918 0 : &me,
1919 0 : instruction->update_commission,
1920 0 : signers,
1921 0 : signers_cnt,
1922 0 : epoch_schedule,
1923 0 : clock,
1924 0 : delay_commission_updates
1925 0 : );
1926 :
1927 0 : break;
1928 0 : }
1929 :
1930 : /* Vote
1931 : *
1932 : * Instruction:
1933 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L49
1934 : */
1935 0 : case fd_vote_instruction_enum_vote:;
1936 : /* clang-format off */
1937 0 : __attribute__((fallthrough));
1938 : /* clang-format on */
1939 :
1940 : /* VoteSwitch
1941 : *
1942 : * Instruction:
1943 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L81
1944 : *
1945 : * Processor:
1946 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L154
1947 : */
1948 0 : case fd_vote_instruction_enum_vote_switch: {
1949 0 : if( FD_FEATURE_ACTIVE_BANK( ctx->bank, deprecate_legacy_vote_ixs ) ) {
1950 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
1951 0 : }
1952 :
1953 0 : fd_vote_t * vote;
1954 0 : if( instruction->discriminant == fd_vote_instruction_enum_vote ) {
1955 0 : vote = &instruction->vote;
1956 0 : } else if( instruction->discriminant == fd_vote_instruction_enum_vote_switch ) {
1957 0 : vote = &instruction->vote_switch.vote;
1958 0 : } else {
1959 0 : FD_LOG_CRIT(( "unsupported instruction discriminant: %u", instruction->discriminant ));
1960 0 : }
1961 :
1962 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L155
1963 0 : int err;
1964 0 : err = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_slot_hashes_id );
1965 0 : if( FD_UNLIKELY( err ) ) return err;
1966 :
1967 0 : if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
1968 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1969 0 : }
1970 :
1971 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L157
1972 0 : err = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id );
1973 0 : if( FD_UNLIKELY( err ) ) return err;
1974 0 : fd_sol_sysvar_clock_t clock_;
1975 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
1976 0 : if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1977 :
1978 0 : fd_slot_hashes_t slot_hashes_[1];
1979 0 : fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes_view( ctx->sysvar_cache, slot_hashes_ );
1980 0 : if( FD_UNLIKELY( !slot_hashes ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1981 0 : rc = process_vote_with_account(
1982 0 : ctx,
1983 0 : &me,
1984 0 : target_version,
1985 0 : slot_hashes,
1986 0 : clock,
1987 0 : vote,
1988 0 : signers,
1989 0 : signers_cnt
1990 0 : );
1991 :
1992 0 : break;
1993 0 : }
1994 :
1995 : /* UpdateVoteState
1996 : *
1997 : * Instruction:
1998 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L100
1999 : */
2000 0 : case fd_vote_instruction_enum_update_vote_state:;
2001 : /* clang-format off */
2002 0 : __attribute__((fallthrough));
2003 : /* clang-format on */
2004 :
2005 : /* UpdateVoteStateSwitch
2006 : *
2007 : * Instruction:
2008 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L107
2009 : *
2010 : * Processor:
2011 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L169
2012 : */
2013 0 : case fd_vote_instruction_enum_update_vote_state_switch: {
2014 0 : if( FD_FEATURE_ACTIVE_BANK( ctx->bank, deprecate_legacy_vote_ixs ) ) {
2015 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2016 0 : }
2017 :
2018 0 : fd_vote_state_update_t * vote_state_update;
2019 0 : switch( instruction->discriminant ) {
2020 0 : case fd_vote_instruction_enum_update_vote_state:
2021 0 : vote_state_update = &instruction->update_vote_state;
2022 0 : break;
2023 0 : case fd_vote_instruction_enum_update_vote_state_switch:
2024 0 : vote_state_update = &instruction->update_vote_state_switch.vote_state_update;
2025 0 : break;
2026 0 : default:
2027 0 : FD_LOG_CRIT(( "unsupported instruction discriminant: %u", instruction->discriminant ));
2028 0 : }
2029 :
2030 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L171
2031 0 : if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
2032 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2033 0 : }
2034 :
2035 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L172
2036 0 : fd_sol_sysvar_clock_t clock_;
2037 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
2038 0 : if( FD_UNLIKELY( !clock ) )
2039 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2040 :
2041 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L173
2042 0 : fd_slot_hashes_t slot_hashes_[1];
2043 0 : fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes_view( ctx->sysvar_cache, slot_hashes_ );
2044 0 : if( FD_UNLIKELY( !slot_hashes ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2045 0 : rc = process_vote_state_update(
2046 0 : ctx,
2047 0 : &me,
2048 0 : target_version,
2049 0 : slot_hashes,
2050 0 : clock,
2051 0 : vote_state_update,
2052 0 : signers,
2053 0 : signers_cnt
2054 0 : );
2055 :
2056 0 : break;
2057 0 : }
2058 :
2059 : /* CompactUpdateVoteState
2060 : *
2061 : * Instruction:
2062 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L139
2063 : *
2064 : * Notes:
2065 : * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
2066 : * - Feature gated, but live on mainnet.
2067 : */
2068 0 : case fd_vote_instruction_enum_compact_update_vote_state:;
2069 0 : __attribute__((fallthrough));
2070 :
2071 : /* CompactUpdateVoteStateSwitch
2072 : *
2073 : * Instruction:
2074 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L146
2075 : *
2076 : * Processor:
2077 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L183
2078 : *
2079 : * Notes:
2080 : * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
2081 : * - Feature gated, but live on mainnet.
2082 : */
2083 0 : case fd_vote_instruction_enum_compact_update_vote_state_switch: {
2084 : /* https://github.com/anza-xyz/agave/blob/dc4b9dcbbf859ff48f40d00db824bde063fdafcc/programs/vote/src/vote_processor.rs#L183-L191 */
2085 0 : if( FD_FEATURE_ACTIVE_BANK( ctx->bank, deprecate_legacy_vote_ixs ) ) {
2086 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2087 0 : }
2088 :
2089 0 : fd_compact_vote_state_update_t * vote_state_update = NULL;
2090 0 : if( instruction->discriminant == fd_vote_instruction_enum_compact_update_vote_state ) {
2091 0 : vote_state_update = &instruction->compact_update_vote_state;
2092 0 : } else if( instruction->discriminant ==
2093 0 : fd_vote_instruction_enum_compact_update_vote_state_switch ) {
2094 0 : vote_state_update =
2095 0 : &instruction->compact_update_vote_state_switch.compact_vote_state_update;
2096 0 : }
2097 :
2098 0 : fd_vote_state_update_t vote_update = {0};
2099 0 : if( FD_UNLIKELY( !fd_vote_decode_compact_update( vote_state_update, &vote_update, ctx ) ) )
2100 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2101 :
2102 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L185
2103 0 : if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
2104 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2105 0 : }
2106 :
2107 0 : fd_sol_sysvar_clock_t clock_;
2108 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
2109 0 : if( FD_UNLIKELY( !clock ) )
2110 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2111 :
2112 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L187
2113 0 : fd_slot_hashes_t slot_hashes_[1];
2114 0 : fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes_view( ctx->sysvar_cache, slot_hashes_ );
2115 0 : if( FD_UNLIKELY( !slot_hashes ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2116 0 : rc = process_vote_state_update(
2117 0 : ctx,
2118 0 : &me,
2119 0 : target_version,
2120 0 : slot_hashes,
2121 0 : clock,
2122 0 : &vote_update,
2123 0 : signers,
2124 0 : signers_cnt
2125 0 : );
2126 :
2127 0 : break;
2128 0 : }
2129 :
2130 : /* TowerSync(Switch)
2131 : *
2132 : * Instruction:
2133 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L151-L157
2134 : *
2135 : * Processor:
2136 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L196-L215
2137 : */
2138 :
2139 0 : case fd_vote_instruction_enum_tower_sync:
2140 0 : case fd_vote_instruction_enum_tower_sync_switch: {
2141 0 : fd_tower_sync_t * tower_sync = (instruction->discriminant == fd_vote_instruction_enum_tower_sync)
2142 0 : ? &instruction->tower_sync
2143 0 : : &instruction->tower_sync_switch.tower_sync;
2144 :
2145 0 : if( FD_UNLIKELY( !fd_sysvar_cache_slot_hashes_is_valid( ctx->sysvar_cache ) ) ) {
2146 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2147 0 : }
2148 :
2149 0 : fd_sol_sysvar_clock_t clock_;
2150 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
2151 0 : if( FD_UNLIKELY( !clock ) ) {
2152 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2153 0 : }
2154 :
2155 0 : fd_slot_hashes_t slot_hashes_[1];
2156 0 : fd_slot_hashes_t const * slot_hashes = fd_sysvar_cache_slot_hashes_view( ctx->sysvar_cache, slot_hashes_ );
2157 0 : if( FD_UNLIKELY( !slot_hashes ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2158 0 : rc = process_tower_sync(
2159 0 : ctx,
2160 0 : &me,
2161 0 : target_version,
2162 0 : slot_hashes,
2163 0 : clock,
2164 0 : tower_sync,
2165 0 : signers,
2166 0 : signers_cnt
2167 0 : );
2168 :
2169 0 : break;
2170 0 : }
2171 :
2172 : /* Withdraw
2173 : *
2174 : * Instruction:
2175 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L57
2176 : *
2177 : * Processor:
2178 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L216
2179 : */
2180 0 : case fd_vote_instruction_enum_withdraw: {
2181 0 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) ) {
2182 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
2183 0 : break;
2184 0 : }
2185 0 : fd_rent_t rent_;
2186 0 : fd_rent_t const * rent_sysvar = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
2187 0 : if( FD_UNLIKELY( !rent_sysvar ) )
2188 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2189 0 : fd_sol_sysvar_clock_t clock_;
2190 0 : fd_sol_sysvar_clock_t const * clock_sysvar = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
2191 0 : if( FD_UNLIKELY( !clock_sysvar ) )
2192 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2193 :
2194 0 : int deinitialized = 0;
2195 0 : rc = withdraw(
2196 0 : ctx,
2197 0 : &me,
2198 0 : target_version,
2199 0 : instruction->withdraw,
2200 0 : 1UL,
2201 0 : signers,
2202 0 : signers_cnt,
2203 0 : rent_sysvar,
2204 0 : clock_sysvar,
2205 0 : &deinitialized
2206 0 : );
2207 :
2208 0 : if( FD_LIKELY( !rc && deinitialized ) ) {
2209 0 : ctx->txn_out->accounts.new_vote[ ctx->instr->accounts[0].index_in_transaction ] = 0;
2210 0 : ctx->txn_out->accounts.rm_vote[ ctx->instr->accounts[0].index_in_transaction ] = 1;
2211 0 : }
2212 :
2213 :
2214 0 : break;
2215 0 : }
2216 :
2217 : /* AuthorizeChecked
2218 : *
2219 : * Instruction:
2220 : * https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/vote/instruction.rs#L93
2221 : *
2222 : * Processor:
2223 : * https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L234
2224 : *
2225 : * Notes:
2226 : * - Up to three signers: the vote authority, the authorized withdrawer, and the new authority.
2227 : * - Feature gated, but live on mainnet.
2228 : */
2229 0 : case fd_vote_instruction_enum_authorize_checked: {
2230 0 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 4 ) ) {
2231 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
2232 0 : break;
2233 0 : }
2234 :
2235 : // https://github.com/anza-xyz/agave/blob/v2.1.14/programs/vote/src/vote_processor.rs#L243-L245
2236 0 : fd_pubkey_t const * voter_pubkey = NULL;
2237 0 : rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 3UL, &voter_pubkey );
2238 0 : if( FD_UNLIKELY( rc ) ) return rc;
2239 :
2240 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L239
2241 0 : if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3, &rc ) ) ) {
2242 : /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
2243 0 : if( FD_UNLIKELY( !!rc ) ) break;
2244 :
2245 0 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2246 0 : break;
2247 0 : }
2248 :
2249 : // https://github.com/anza-xyz/agave/blob/v2.0.1/programs/vote/src/vote_processor.rs#L242
2250 0 : rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_clock_id );
2251 0 : if( FD_UNLIKELY( rc ) ) return rc;
2252 0 : fd_sol_sysvar_clock_t clock_;
2253 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
2254 0 : if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2255 :
2256 0 : rc = authorize(
2257 0 : ctx,
2258 0 : &me,
2259 0 : target_version,
2260 0 : voter_pubkey,
2261 0 : &instruction->authorize_checked,
2262 0 : signers,
2263 0 : signers_cnt,
2264 0 : clock,
2265 0 : is_vote_authorize_with_bls_enabled
2266 0 : );
2267 0 : break;
2268 0 : }
2269 :
2270 : /* InitializeAccountV2
2271 : *
2272 : * Instruction:
2273 : * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L195-L200
2274 : *
2275 : * Processor:
2276 : * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L307-L324
2277 : *
2278 : * Notes:
2279 : * - The code is identical to InitializeAccount, except calling the actual initialize_account_v2
2280 : * - Feature gated.
2281 : */
2282 6 : case fd_vote_instruction_enum_initialize_account_v2: {
2283 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L308-L310 */
2284 6 : if( FD_UNLIKELY( !is_init_account_v2_enabled ) ) {
2285 6 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2286 6 : }
2287 :
2288 0 : rc = fd_sysvar_instr_acct_check( ctx, 1, &fd_sysvar_rent_id );
2289 0 : if( FD_UNLIKELY( rc ) ) return rc;
2290 0 : fd_rent_t rent_;
2291 0 : fd_rent_t const * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
2292 0 : if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2293 :
2294 0 : if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &me ) <
2295 0 : fd_rent_exempt_minimum_balance( rent, fd_borrowed_account_get_data_len( &me ) ) ) )
2296 0 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
2297 :
2298 0 : rc = fd_sysvar_instr_acct_check( ctx, 2, &fd_sysvar_clock_id );
2299 0 : if( FD_UNLIKELY( rc ) ) return rc;
2300 0 : fd_sol_sysvar_clock_t clock_;
2301 0 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock_read( ctx->sysvar_cache, &clock_ );
2302 0 : if( FD_UNLIKELY( !clock ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2303 :
2304 0 : rc = initialize_account_v2( ctx, &me, target_version, &instruction->initialize_account_v2, signers, signers_cnt, clock );
2305 :
2306 0 : if( FD_LIKELY( !rc ) ) {
2307 0 : ctx->txn_out->accounts.new_vote[ ctx->instr->accounts[0].index_in_transaction ] = 1;
2308 0 : ctx->txn_out->accounts.rm_vote[ ctx->instr->accounts[0].index_in_transaction ] = 0;
2309 0 : }
2310 :
2311 0 : break;
2312 0 : }
2313 :
2314 : /* UpdateCommissionBps (commission_rate_in_basis_points feature)
2315 : *
2316 : * Instruction:
2317 : * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L212-L221
2318 : *
2319 : * Processor:
2320 : * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L325-L347
2321 : *
2322 : */
2323 3 : case fd_vote_instruction_enum_update_commission_bps: {
2324 3 : if( FD_UNLIKELY( !commission_rate_in_basis_points
2325 3 : || !delay_commission_updates ) ) {
2326 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2327 0 : }
2328 :
2329 3 : rc = update_commission_bps( ctx, &me, target_version, &instruction->update_commission_bps, signers, signers_cnt, block_revenue_sharing );
2330 :
2331 3 : break;
2332 3 : }
2333 :
2334 : /* UpdateCommissionCollector (SIMD-0232)
2335 : *
2336 : * Instruction:
2337 : * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L202-L210
2338 : *
2339 : * Processor:
2340 : * https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_processor.rs#L383-L408
2341 : *
2342 : * Notes:
2343 : * - Feature gated on custom_commission_collector
2344 : */
2345 72 : case fd_vote_instruction_enum_update_commission_collector: {
2346 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_processor.rs#L384-L390 */
2347 72 : if( FD_UNLIKELY( !custom_commission_collector ) ) {
2348 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2349 3 : }
2350 :
2351 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_processor.rs#L392 */
2352 69 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 3 ) ) {
2353 3 : rc = FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
2354 3 : break;
2355 3 : }
2356 :
2357 : /* If instruction account 1 is the vote account itself, no account
2358 : is borrowed.
2359 : https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_processor.rs#L83-L98 */
2360 66 : fd_pubkey_t const * collector_key = NULL;
2361 66 : rc = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 1, &collector_key );
2362 66 : if( FD_UNLIKELY( rc ) ) return rc;
2363 :
2364 66 : fd_guarded_borrowed_account_t collector = {0};
2365 66 : fd_borrowed_account_t const * collector_account = NULL;
2366 66 : if( !fd_pubkey_eq( collector_key, (fd_pubkey_t const *)me.acc->pubkey ) ) {
2367 51 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 1, &collector );
2368 51 : collector_account = &collector;
2369 51 : }
2370 :
2371 : /* https://github.com/anza-xyz/agave/blob/v4.2.0-beta.2/programs/vote/src/vote_processor.rs#L395-L398 */
2372 66 : fd_rent_t rent_;
2373 66 : fd_rent_t const * rent = fd_sysvar_cache_rent_read( ctx->sysvar_cache, &rent_ );
2374 66 : if( FD_UNLIKELY( !rent ) ) return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2375 :
2376 66 : rc = update_commission_collector(
2377 66 : ctx,
2378 66 : &me,
2379 66 : target_version,
2380 66 : collector_account,
2381 66 : &instruction->update_commission_collector,
2382 66 : signers,
2383 66 : signers_cnt,
2384 66 : rent
2385 66 : );
2386 :
2387 66 : break;
2388 66 : }
2389 :
2390 : /* DepositDelegatorRewards
2391 : *
2392 : * Instruction:
2393 : * https://github.com/anza-xyz/solana-sdk/blob/vote-interface%40v5.0.0/vote-interface/src/instruction.rs#L223-L228
2394 : *
2395 : * Processor:
2396 : * https://github.com/anza-xyz/agave/blob/v4.0.0-alpha.0/programs/vote/src/vote_processor.rs#L377-L395
2397 : *
2398 : * Notes:
2399 : * - Unimplemented (gated on block_revenue_sharing)
2400 : */
2401 0 : case fd_vote_instruction_enum_deposit_delegator_rewards: {
2402 0 : if( FD_UNLIKELY( !commission_rate_in_basis_points
2403 0 : || !custom_commission_collector
2404 0 : || !block_revenue_sharing ) ) {
2405 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2406 0 : }
2407 :
2408 : /* TODO: fill in when implementing block_revenue_sharing */
2409 0 : FD_LOG_CRIT(( "unimplemented: deposit_delegator_rewards" ));
2410 0 : }
2411 :
2412 0 : default:
2413 0 : FD_LOG_CRIT(( "unsupported vote instruction: %u", instruction->discriminant ));
2414 114 : }
2415 :
2416 105 : return rc;
2417 114 : }
|