Line data Source code
1 : #define FD_SCRATCH_USE_HANDHOLDING 1
2 : #include <limits.h>
3 :
4 : #include "../../../util/bits/fd_sat.h"
5 : #include "../../../util/bits/fd_uwide.h"
6 : #include "../fd_account.h"
7 : #include "../fd_executor.h"
8 : #include "../fd_pubkey_utils.h"
9 : #include "../fd_system_ids.h"
10 :
11 : #include "fd_stake_program.h"
12 : #include "fd_vote_program.h"
13 : #include "../sysvar/fd_sysvar_epoch_schedule.h"
14 : #include "../sysvar/fd_sysvar_rent.h"
15 :
16 : /* A note on fd_borrowed_account_acquire_write:
17 :
18 : The stake program uses this function to prevent aliasing of accounts.
19 : (When the same account is passed via multiple instruction account
20 : indexes.) Internally, it acquires a transaction-wide mutex on the
21 : account. If called twice on the same account while the mutex is
22 : still locked, it returns an "AccountBorrowFailed" error.
23 :
24 : There is no exact equivalent to this in Agave/Rust.
25 :
26 : let handle = instruction_context.try_borrow_instruction_account(...)
27 :
28 : The above creates the lock on the account. However, that lock is
29 : **implicitly** released when 'handle' goes out of scope. Firedancer
30 : releases the handle **explicitly**. */
31 :
32 : /**********************************************************************/
33 : /* Errors */
34 : /**********************************************************************/
35 :
36 : // DO NOT REORDER: https://github.com/bincode-org/bincode/blob/trunk/docs/spec.md#enums
37 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L28
38 : #define FD_STAKE_ERR_NO_CREDITS_TO_REDEEM ( 0 )
39 81 : #define FD_STAKE_ERR_LOCKUP_IN_FORCE ( 1 )
40 219 : #define FD_STAKE_ERR_ALREADY_DEACTIVATED ( 2 )
41 66 : #define FD_STAKE_ERR_TOO_SOON_TO_REDELEGATE ( 3 )
42 0 : #define FD_STAKE_ERR_INSUFFICIENT_STAKE ( 4 )
43 561 : #define FD_STAKE_ERR_MERGE_TRANSIENT_STAKE ( 5 )
44 303 : #define FD_STAKE_ERR_MERGE_MISMATCH ( 6 )
45 39 : #define FD_STAKE_ERR_CUSTODIAN_MISSING ( 7 )
46 36 : #define FD_STAKE_ERR_CUSTODIAN_SIGNATURE_MISSING ( 8 )
47 189 : #define FD_STAKE_ERR_INSUFFICIENT_REFERENCE_VOTES ( 9 )
48 27 : #define FD_STAKE_ERR_VOTE_ADDRESS_MISMATCH ( 10 )
49 204 : #define FD_STAKE_ERR_MINIMUM_DELIQUENT_EPOCHS_FOR_DEACTIVATION_NOT_MET ( 11 )
50 213 : #define FD_STAKE_ERR_INSUFFICIENT_DELEGATION ( 12 )
51 : #define FD_STAKE_ERR_REDELEGATE_TRANSIENT_OR_INACTIVE_STAKE ( 13 )
52 : #define FD_STAKE_ERR_REDELEGATE_TO_SAME_VOTE_ACCOUNT ( 14 )
53 : #define FD_STAKE_ERR_REDELEGATED_STAKE_MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED ( 15 )
54 234 : #define FD_STAKE_ERR_EPOCH_REWARDS_ACTIVE ( 16 )
55 :
56 : /**********************************************************************/
57 : /* Constants */
58 : /**********************************************************************/
59 :
60 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/lib.rs#L31
61 3984 : #define MINIMUM_DELEGATION_SOL ( 1 )
62 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/native_token.rs#L6
63 3984 : #define LAMPORTS_PER_SOL ( 1000000000 )
64 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/mod.rs#L18
65 1119 : #define MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION ( 5 )
66 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L26-L28
67 5379 : #define DEFAULT_WARMUP_COOLDOWN_RATE ( 0.25 )
68 5169 : #define NEW_WARMUP_COOLDOWN_RATE ( 0.09 )
69 0 : #define DEFAULT_SLASH_PENALTY ( 12 )
70 :
71 : #define STAKE_AUTHORIZE_STAKER \
72 4104 : ( ( fd_stake_authorize_t ){ .discriminant = fd_stake_authorize_enum_staker, .inner = {0} } )
73 : #define STAKE_AUTHORIZE_WITHDRAWER \
74 477 : ( ( fd_stake_authorize_t ){ .discriminant = fd_stake_authorize_enum_withdrawer, .inner = {0} } )
75 :
76 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L51
77 : #define DEFAULT_COMPUTE_UNITS 750UL
78 :
79 : /**********************************************************************/
80 : /* MergeKind */
81 : /**********************************************************************/
82 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1074-L1079
83 : struct merge_kind_inactive {
84 : fd_stake_meta_t meta;
85 : ulong active_stake;
86 : fd_stake_flags_t stake_flags;
87 : };
88 : typedef struct merge_kind_inactive merge_kind_inactive_t;
89 :
90 : struct merge_kind_activation_epoch {
91 : fd_stake_meta_t meta;
92 : fd_stake_t stake;
93 : fd_stake_flags_t stake_flags;
94 : };
95 : typedef struct merge_kind_activation_epoch merge_kind_activation_epoch_t;
96 :
97 : struct merge_kind_fully_active {
98 : fd_stake_meta_t meta;
99 : fd_stake_t stake;
100 : };
101 : typedef struct merge_kind_fully_active merge_kind_fully_active_t;
102 :
103 : union merge_kind_inner {
104 : merge_kind_inactive_t inactive;
105 : merge_kind_activation_epoch_t activation_epoch;
106 : merge_kind_fully_active_t fully_active;
107 : };
108 : typedef union merge_kind_inner merge_kind_inner_t;
109 :
110 : struct merge_kind {
111 : uint discriminant;
112 : merge_kind_inner_t inner;
113 : };
114 : typedef struct merge_kind merge_kind_t;
115 :
116 : enum { merge_kind_inactive = 0, merge_kind_activation_epoch = 1, merge_kind_fully_active = 2 };
117 :
118 : typedef fd_stake_history_entry_t stake_activation_status_t;
119 :
120 : struct effective_activating {
121 : ulong effective;
122 : ulong activating;
123 : };
124 : typedef struct effective_activating effective_activating_t;
125 :
126 : /**********************************************************************/
127 : /* Bincode */
128 : /**********************************************************************/
129 :
130 : static int
131 : get_state( fd_borrowed_account_t const * self,
132 : fd_valloc_t valloc,
133 11625 : fd_stake_state_v2_t * out ) {
134 11625 : int rc;
135 :
136 11625 : fd_bincode_decode_ctx_t bincode_ctx;
137 11625 : bincode_ctx.data = self->const_data;
138 11625 : bincode_ctx.dataend = self->const_data + self->const_meta->dlen;
139 11625 : bincode_ctx.valloc = valloc;
140 :
141 11625 : rc = fd_stake_state_v2_decode( out, &bincode_ctx );
142 11625 : if( FD_UNLIKELY( rc!=FD_BINCODE_SUCCESS ) ) return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
143 :
144 10857 : return 0;
145 11625 : }
146 :
147 : static int
148 : set_state( fd_exec_instr_ctx_t const * ctx,
149 : ulong acct_idx,
150 3555 : fd_stake_state_v2_t const * state ) {
151 :
152 3555 : uchar * data = NULL;
153 3555 : ulong dlen = 0UL;
154 :
155 3555 : int err = fd_account_get_data_mut( ctx, acct_idx, &data, &dlen );
156 3555 : if( FD_UNLIKELY( err ) ) return err;
157 :
158 3285 : ulong serialized_size = fd_stake_state_v2_size( state );
159 3285 : if( FD_UNLIKELY( serialized_size>dlen ) )
160 0 : return FD_EXECUTOR_INSTR_ERR_ACC_DATA_TOO_SMALL;
161 :
162 3285 : fd_borrowed_account_t * account = NULL;
163 3285 : do {
164 3285 : int err = fd_instr_borrowed_account_modify_idx( ctx, acct_idx, serialized_size, &account );
165 3285 : if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_instr_borrowed_account_modify_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
166 3285 : } while(0);
167 :
168 3285 : fd_bincode_encode_ctx_t encode = {
169 3285 : .data = account->data,
170 3285 : .dataend = account->data + serialized_size,
171 3285 : };
172 3285 : do {
173 3285 : int err = fd_stake_state_v2_encode( state, &encode );
174 3285 : if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_stake_state_v2_encode failed" ));
175 3285 : } while(0);
176 :
177 3285 : return 0;
178 3285 : }
179 :
180 : /**********************************************************************/
181 : /* mod stake */
182 : /**********************************************************************/
183 :
184 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/lib.rs#L29
185 : static inline ulong
186 3984 : get_minimum_delegation( fd_exec_slot_ctx_t const * slot_ctx /* feature set */ ) {
187 3984 : return fd_ulong_if( FD_FEATURE_ACTIVE( slot_ctx, stake_raise_minimum_delegation_to_1_sol ),
188 3984 : MINIMUM_DELEGATION_SOL * LAMPORTS_PER_SOL,
189 3984 : 1 );
190 3984 : }
191 :
192 : /**********************************************************************/
193 : /* mod stake/state */
194 : /**********************************************************************/
195 :
196 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L30
197 : static inline double
198 5169 : warmup_cooldown_rate( ulong current_epoch, ulong * new_rate_activation_epoch ) {
199 5169 : return fd_double_if( current_epoch <
200 5169 : ( new_rate_activation_epoch ? *new_rate_activation_epoch : ULONG_MAX ),
201 5169 : DEFAULT_WARMUP_COOLDOWN_RATE,
202 5169 : NEW_WARMUP_COOLDOWN_RATE );
203 5169 : }
204 :
205 : /**********************************************************************/
206 : /* validated */
207 : /**********************************************************************/
208 :
209 : struct validated_delegated_info {
210 : ulong stake_amount;
211 : };
212 : typedef struct validated_delegated_info validated_delegated_info_t;
213 :
214 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L963
215 : static int
216 : validate_delegated_amount( fd_borrowed_account_t * account,
217 : fd_stake_meta_t const * meta,
218 : fd_exec_slot_ctx_t const * slot_ctx,
219 : validated_delegated_info_t * out,
220 630 : uint * custom_err ) {
221 630 : ulong stake_amount = fd_ulong_sat_sub( account->const_meta->info.lamports, meta->rent_exempt_reserve );
222 :
223 630 : if( FD_UNLIKELY( stake_amount<get_minimum_delegation( slot_ctx ) ) ) {
224 150 : *custom_err = FD_STAKE_ERR_INSUFFICIENT_DELEGATION;
225 150 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
226 150 : }
227 480 : out->stake_amount = stake_amount;
228 480 : return 0;
229 630 : }
230 :
231 : struct validated_split_info {
232 : ulong source_remaining_balance;
233 : ulong destination_rent_exempt_reserve;
234 : };
235 : typedef struct validated_split_info validated_split_info_t;
236 :
237 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L992
238 : static int
239 : validate_split_amount( fd_exec_instr_ctx_t const * invoke_context,
240 : uchar source_account_index,
241 : uchar destination_account_index,
242 : ulong lamports,
243 : fd_stake_meta_t const * source_meta,
244 : ulong additional_required_lamports,
245 : int source_is_active,
246 1530 : validated_split_info_t * out ) {
247 :
248 1530 : ulong source_lamports = 0;
249 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1003-L1004
250 6120 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( invoke_context, source_account_index, source_account ) {
251 :
252 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1005
253 1530 : source_lamports = source_account->const_meta->info.lamports;
254 :
255 1530 : } FD_BORROWED_ACCOUNT_DROP( source_account );
256 :
257 1530 : ulong destination_lamports = 0;
258 1530 : ulong destination_data_len = 0;
259 :
260 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1007-L1008
261 6120 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( invoke_context, destination_account_index, destination_account ) {
262 :
263 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1009-1010
264 1530 : destination_lamports = destination_account->const_meta->info.lamports;
265 1530 : destination_data_len = destination_account->const_meta->dlen;
266 :
267 1530 : } FD_BORROWED_ACCOUNT_DROP( destination_account );
268 :
269 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1013-L1021
270 1530 : if( FD_UNLIKELY( lamports==0 ) ) return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
271 1467 : if( FD_UNLIKELY( lamports>source_lamports ) ) return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
272 :
273 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1027-L1040
274 1467 : ulong source_minimum_balance =
275 1467 : fd_ulong_sat_add( source_meta->rent_exempt_reserve, additional_required_lamports );
276 1467 : ulong source_remaining_balance = fd_ulong_sat_sub( source_lamports, lamports );
277 :
278 1467 : if( FD_LIKELY( source_remaining_balance==0 ) ) {
279 1038 : } else if( source_remaining_balance<source_minimum_balance ) {
280 117 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
281 921 : } else {
282 1350 : };
283 :
284 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1042
285 1350 : fd_rent_t const * rent = fd_sysvar_cache_rent( invoke_context->slot_ctx->sysvar_cache );
286 1350 : if( FD_UNLIKELY( !rent ) )
287 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
288 :
289 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1043
290 1350 : ulong destination_rent_exempt_reserve =
291 1350 : fd_rent_exempt_minimum_balance( rent, destination_data_len );
292 :
293 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1048
294 1350 : if( FD_UNLIKELY(
295 1350 : FD_FEATURE_ACTIVE( invoke_context->slot_ctx, require_rent_exempt_split_destination ) &&
296 1350 : source_is_active && source_remaining_balance!=0 &&
297 1350 : destination_lamports<destination_rent_exempt_reserve ) ) {
298 258 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
299 258 : }
300 :
301 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1059-L1066
302 1092 : ulong destination_minimum_balance =
303 1092 : fd_ulong_sat_add( destination_rent_exempt_reserve, additional_required_lamports );
304 1092 : ulong destination_balance_deficit =
305 1092 : fd_ulong_sat_sub( destination_minimum_balance, destination_lamports );
306 1092 : if( FD_UNLIKELY( lamports<destination_balance_deficit ) ) {
307 168 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
308 168 : }
309 :
310 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1067-L1071
311 924 : out->source_remaining_balance = source_remaining_balance;
312 924 : out->destination_rent_exempt_reserve = destination_rent_exempt_reserve;
313 924 : return 0;
314 1092 : }
315 :
316 : /**********************************************************************/
317 : /* impl Lockup */
318 : /**********************************************************************/
319 :
320 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L270
321 : static inline int
322 : lockup_is_in_force( fd_stake_lockup_t const * self,
323 : fd_sol_sysvar_clock_t const * clock,
324 1875 : fd_pubkey_t const * custodian ) {
325 : // FIXME FD_LIKELY
326 1875 : if( custodian && !memcmp( custodian, &self->custodian, sizeof( fd_pubkey_t ) ) ) {
327 45 : return 0;
328 45 : }
329 1830 : return self->unix_timestamp>clock->unix_timestamp || self->epoch>clock->epoch;
330 1875 : }
331 :
332 : /**********************************************************************/
333 : /* impl Authorized */
334 : /**********************************************************************/
335 :
336 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L359
337 : static inline int
338 : authorized_check( fd_stake_authorized_t const * self,
339 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
340 4809 : fd_stake_authorize_t stake_authorize ) {
341 : /* clang-format off */
342 4809 : switch( stake_authorize.discriminant ) {
343 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L365
344 4104 : case fd_stake_authorize_enum_staker:
345 4104 : if( FD_LIKELY( fd_instr_signers_contains( signers, &self->staker ) ) ) {
346 3168 : return 0;
347 3168 : }
348 936 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
349 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L366
350 705 : case fd_stake_authorize_enum_withdrawer:
351 705 : if( FD_LIKELY( fd_instr_signers_contains( signers, &self->withdrawer ) ) ) {
352 555 : return 0;
353 555 : }
354 150 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
355 0 : default:
356 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
357 4809 : }
358 : /* clang-format on */
359 4809 : }
360 :
361 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L371
362 : static int
363 : authorized_authorize( fd_stake_authorized_t * self,
364 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
365 : fd_pubkey_t const * new_authorized,
366 : fd_stake_authorize_t const * stake_authorize,
367 : fd_stake_lockup_custodian_args_t const * lockup_custodian_args,
368 747 : /* out */ uint * custom_err ) {
369 747 : int rc;
370 747 : switch( stake_authorize->discriminant ) {
371 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L379
372 396 : case fd_stake_authorize_enum_staker:
373 396 : if( FD_UNLIKELY( !fd_instr_signers_contains( signers, &self->staker ) &&
374 396 : !fd_instr_signers_contains( signers, &self->withdrawer ) ) ) {
375 216 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
376 216 : }
377 180 : self->staker = *new_authorized;
378 180 : break;
379 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L386
380 351 : case fd_stake_authorize_enum_withdrawer:
381 351 : if( FD_LIKELY( lockup_custodian_args ) ) {
382 351 : fd_stake_lockup_t const * lockup = &lockup_custodian_args->lockup;
383 351 : fd_sol_sysvar_clock_t const * clock = &lockup_custodian_args->clock;
384 351 : fd_pubkey_t const * custodian = lockup_custodian_args->custodian;
385 :
386 : // FIXME FD_LIKELY
387 351 : if( lockup_is_in_force( lockup, clock, NULL ) ) {
388 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L389-L402
389 129 : if( !custodian ) { // FIXME FD_LIKELY
390 39 : *custom_err = FD_STAKE_ERR_CUSTODIAN_MISSING;
391 39 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
392 90 : } else {
393 90 : if( FD_UNLIKELY( !fd_instr_signers_contains( signers, custodian ) ) ) {
394 36 : *custom_err = FD_STAKE_ERR_CUSTODIAN_SIGNATURE_MISSING;
395 36 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
396 36 : }
397 :
398 54 : if( FD_UNLIKELY( lockup_is_in_force( lockup, clock, custodian ) ) ) {
399 48 : *custom_err = FD_STAKE_ERR_LOCKUP_IN_FORCE;
400 48 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
401 48 : }
402 54 : }
403 129 : }
404 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L405
405 228 : rc = authorized_check( self, signers, *stake_authorize );
406 228 : if( FD_UNLIKELY( rc ) ) return rc;
407 144 : self->withdrawer = *new_authorized;
408 144 : }
409 747 : }
410 324 : return 0;
411 747 : }
412 :
413 : /**********************************************************************/
414 : /* impl Meta */
415 : /**********************************************************************/
416 :
417 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L482
418 : static inline int
419 : set_lockup_meta( fd_stake_meta_t * self,
420 : fd_lockup_args_t const * lockup,
421 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
422 525 : fd_sol_sysvar_clock_t const * clock ) {
423 : // FIXME FD_LIKELY
424 525 : if( lockup_is_in_force( &self->lockup, clock, NULL ) ) {
425 333 : if( !fd_instr_signers_contains( signers, &self->lockup.custodian ) ) {
426 270 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
427 270 : }
428 333 : } else if( !fd_instr_signers_contains( signers, &self->authorized.withdrawer ) ) {
429 138 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
430 138 : }
431 :
432 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L498-L506
433 117 : if( lockup->unix_timestamp ) self->lockup.unix_timestamp = *lockup->unix_timestamp;
434 117 : if( lockup->epoch ) self->lockup.epoch = *lockup->epoch;
435 117 : if( lockup->custodian ) self->lockup.custodian = *lockup->custodian;
436 117 : return 0;
437 525 : }
438 :
439 : /**********************************************************************/
440 : /* impl Delegation */
441 : /**********************************************************************/
442 :
443 : typedef fd_stake_history_entry_t fd_stake_activation_status_t;
444 :
445 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L728
446 : static effective_activating_t
447 : stake_and_activating( fd_delegation_t const * self,
448 : ulong target_epoch,
449 : fd_stake_history_t const * history,
450 3342 : ulong * new_rate_activation_epoch ) {
451 3342 : ulong delegated_stake = self->stake;
452 :
453 3342 : fd_stake_history_entry_t const * cluster_stake_at_activation_epoch;
454 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L736
455 3342 : if( self->activation_epoch==ULONG_MAX ) {
456 312 : return ( effective_activating_t ){ .effective = delegated_stake, .activating = 0 };
457 3030 : } else if( self->activation_epoch==self->deactivation_epoch ) {
458 270 : return ( effective_activating_t ){ .effective = 0, .activating = 0 };
459 2760 : } else if( target_epoch==self->activation_epoch ) {
460 453 : return ( effective_activating_t ){ .effective = 0, .activating = delegated_stake };
461 2307 : } else if( target_epoch<self->activation_epoch ) {
462 252 : return ( effective_activating_t ){ .effective = 0, .activating = 0 };
463 2055 : } else if( history &&
464 2055 : ( cluster_stake_at_activation_epoch = fd_stake_history_treap_ele_query_const(
465 2055 : history->treap, self->activation_epoch, history->pool ) ) ) {
466 588 : ulong prev_epoch = self->activation_epoch;
467 588 : fd_stake_history_entry_t const * prev_cluster_stake = cluster_stake_at_activation_epoch;
468 :
469 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L763
470 588 : ulong current_epoch;
471 588 : ulong current_effective_stake = 0;
472 4083 : for( ;; ) {
473 4083 : current_epoch = prev_epoch + 1;
474 4083 : if( FD_LIKELY( prev_cluster_stake->activating==0 ) ) { // FIXME always optimize loop break?
475 120 : break;
476 120 : }
477 :
478 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L775-L780
479 3963 : ulong remaining_activating_stake = delegated_stake - current_effective_stake;
480 3963 : double weight = (double)remaining_activating_stake / (double)prev_cluster_stake->activating;
481 3963 : double warmup_cooldown_rate_ =
482 3963 : warmup_cooldown_rate( current_epoch, new_rate_activation_epoch );
483 :
484 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L782-L786
485 3963 : double newly_effective_cluster_stake =
486 3963 : (double)prev_cluster_stake->effective * warmup_cooldown_rate_;
487 3963 : ulong newly_effective_stake =
488 3963 : fd_ulong_max( fd_rust_cast_double_to_ulong( weight * newly_effective_cluster_stake ), 1 );
489 :
490 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L787-L792
491 3963 : current_effective_stake += newly_effective_stake;
492 3963 : if( FD_LIKELY( current_effective_stake>=delegated_stake ) ) {
493 204 : current_effective_stake = delegated_stake;
494 204 : break;
495 204 : }
496 :
497 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L793
498 3759 : if( FD_LIKELY( current_epoch>=target_epoch ||
499 3759 : current_epoch>=self->deactivation_epoch ) ) { // FIXME always optimize loop break
500 264 : break;
501 264 : }
502 :
503 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L796-L801
504 3495 : fd_stake_history_entry_t const * current_cluster_stake =
505 3495 : fd_stake_history_treap_ele_query_const( history->treap, current_epoch, history->pool );
506 3495 : if( FD_UNLIKELY( current_cluster_stake = fd_stake_history_treap_ele_query_const(
507 3495 : history->treap, current_epoch, history->pool ) ) ) {
508 3495 : prev_epoch = current_epoch;
509 3495 : prev_cluster_stake = current_cluster_stake;
510 3495 : } else {
511 : // FIXME always optimize loop break
512 0 : break;
513 0 : }
514 3495 : }
515 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L804-L807
516 588 : return ( effective_activating_t ){ .effective = current_effective_stake,
517 588 : .activating = delegated_stake - current_effective_stake };
518 1467 : } else {
519 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L810
520 1467 : return ( effective_activating_t ){ .effective = delegated_stake, .activating = 0 };
521 1467 : }
522 3342 : }
523 :
524 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L641
525 : static fd_stake_activation_status_t
526 : stake_activating_and_deactivating( fd_delegation_t const * self,
527 : ulong target_epoch,
528 : fd_stake_history_t const * stake_history,
529 3342 : ulong * new_rate_activation_epoch ) {
530 :
531 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L648
532 3342 : effective_activating_t effective_activating =
533 3342 : stake_and_activating( self, target_epoch, stake_history, new_rate_activation_epoch );
534 :
535 3342 : ulong effective_stake = effective_activating.effective;
536 3342 : ulong activating_stake = effective_activating.activating;
537 :
538 3342 : fd_stake_history_entry_t * cluster_stake_at_activation_epoch = NULL;
539 :
540 3342 : fd_stake_history_entry_t k;
541 3342 : k.epoch = self->deactivation_epoch;
542 :
543 : // https://github.com/anza-xyz/agave/blob/v2.0.1/sdk/program/src/stake/state.rs#L652
544 3342 : if( target_epoch<self->deactivation_epoch ) {
545 : // if is bootstrap
546 2292 : if( activating_stake==0 ) {
547 1566 : return ( fd_stake_history_entry_t ){
548 1566 : .effective = effective_stake, .deactivating = 0, .activating = 0 };
549 1566 : } else {
550 726 : return ( fd_stake_history_entry_t ){
551 726 : .effective = effective_stake, .deactivating = 0, .activating = activating_stake };
552 726 : }
553 2292 : } else if( target_epoch==self->deactivation_epoch ) {
554 : // https://github.com/anza-xyz/agave/blob/be16321eb0db3e12a57a32f59febbf54b92ebb7c/sdk/program/src/stake/state.rs#L662
555 318 : return ( fd_stake_history_entry_t ){
556 318 : .effective = effective_stake, .deactivating = effective_stake, .activating = 0 };
557 732 : } else if( stake_history!=NULL ) {
558 : // https://github.com/anza-xyz/agave/blob/be16321eb0db3e12a57a32f59febbf54b92ebb7c/sdk/program/src/stake/state.rs#L665
559 732 : fd_stake_history_entry_t * n =
560 732 : fd_stake_history_treap_ele_query( stake_history->treap, k.epoch, stake_history->pool );
561 :
562 732 : if( NULL!=n ) { cluster_stake_at_activation_epoch = n; }
563 :
564 732 : if( cluster_stake_at_activation_epoch==NULL ) {
565 483 : fd_stake_history_entry_t entry = { .effective = 0, .activating = 0, .deactivating = 0 };
566 :
567 483 : return entry;
568 483 : }
569 249 : ulong prev_epoch = self->deactivation_epoch;
570 249 : fd_stake_history_entry_t * prev_cluster_stake = cluster_stake_at_activation_epoch;
571 :
572 249 : ulong current_epoch;
573 249 : ulong current_effective_stake = effective_stake;
574 1212 : for( ;; ) {
575 1212 : current_epoch = prev_epoch + 1;
576 1212 : if( prev_cluster_stake->deactivating==0 ) break;
577 :
578 1206 : double weight = (double)current_effective_stake / (double)prev_cluster_stake->deactivating;
579 1206 : double warmup_cooldown_rate_ =
580 1206 : warmup_cooldown_rate( current_epoch, new_rate_activation_epoch );
581 :
582 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L697-L700
583 1206 : double newly_not_effective_cluster_stake =
584 1206 : (double)prev_cluster_stake->effective * warmup_cooldown_rate_;
585 1206 : ulong newly_not_effective_stake =
586 1206 : fd_ulong_max( fd_rust_cast_double_to_ulong( weight * newly_not_effective_cluster_stake ), 1 );
587 :
588 1206 : current_effective_stake =
589 1206 : fd_ulong_sat_sub( current_effective_stake, newly_not_effective_stake );
590 1206 : if( current_effective_stake==0 ) break;
591 :
592 1173 : if( current_epoch>=target_epoch ) break;
593 :
594 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L711-L713
595 963 : fd_stake_history_entry_t * current_cluster_stake = NULL;
596 963 : if( ( current_cluster_stake = fd_stake_history_treap_ele_query(
597 963 : stake_history->treap, current_epoch, stake_history->pool ) ) ) {
598 963 : prev_epoch = current_epoch;
599 963 : prev_cluster_stake = current_cluster_stake;
600 963 : } else {
601 0 : break;
602 0 : }
603 963 : }
604 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L720
605 249 : return ( fd_stake_history_entry_t ){ .effective = current_effective_stake,
606 249 : .deactivating = current_effective_stake,
607 249 : .activating = 0 };
608 732 : } else {
609 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L723C16-L723C17
610 0 : return ( fd_stake_history_entry_t ){ .effective = 0, .activating = 0, .deactivating = 0 };
611 0 : }
612 3342 : }
613 :
614 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L630
615 : static inline ulong
616 : delegation_stake( fd_delegation_t const * self,
617 : ulong epoch,
618 : fd_stake_history_t const * history,
619 444 : ulong * new_rate_activation_epoch ) {
620 444 : return stake_activating_and_deactivating( self, epoch, history, new_rate_activation_epoch )
621 444 : .effective;
622 444 : }
623 :
624 : /**********************************************************************/
625 : /* mod tools */
626 : /**********************************************************************/
627 :
628 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/tools.rs#L44
629 : static inline int
630 : acceptable_reference_epoch_credits( fd_vote_epoch_credits_t * epoch_credits,
631 681 : ulong current_epoch ) {
632 681 : ulong len = deq_fd_vote_epoch_credits_t_cnt( epoch_credits );
633 681 : ulong epoch_index[1] = { ULONG_MAX };
634 : // FIXME FD_LIKELY
635 681 : if( !__builtin_usubl_overflow( len, MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION, epoch_index ) ) {
636 558 : ulong epoch = current_epoch;
637 3057 : for( ulong i = len - 1; i>=*epoch_index; i-- ) {
638 2574 : ulong vote_epoch = deq_fd_vote_epoch_credits_t_peek_index( epoch_credits, i )->epoch;
639 2574 : if( vote_epoch!=epoch ) { return 0; }
640 2508 : epoch = fd_ulong_sat_sub( epoch, 1 );
641 2508 : if( i==0 ) break;
642 2508 : }
643 492 : return 1;
644 558 : } else {
645 123 : return 0;
646 123 : };
647 0 : }
648 :
649 : /* https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/tools.rs#L67-L83 */
650 : static inline int
651 468 : eligible_for_deactivate_delinquent( fd_vote_epoch_credits_t * epoch_credits, ulong current_epoch ) {
652 468 : if( FD_LIKELY( deq_fd_vote_epoch_credits_t_empty( epoch_credits ) ) ) {
653 30 : return 1;
654 30 : }
655 :
656 438 : fd_vote_epoch_credits_t * last = deq_fd_vote_epoch_credits_t_peek_tail( epoch_credits );
657 438 : if( FD_LIKELY( !last ) ) {
658 0 : return 1;
659 438 : } else {
660 438 : ulong epoch = last->epoch;
661 438 : ulong minimum_epoch = ULONG_MAX;
662 438 : int res = fd_ulong_checked_sub( current_epoch, MINIMUM_DELINQUENT_EPOCHS_FOR_DEACTIVATION, &minimum_epoch );
663 438 : if( FD_LIKELY( res==0 ) ) {
664 438 : return epoch<=minimum_epoch;
665 438 : } else {
666 0 : return 0;
667 0 : }
668 438 : }
669 438 : }
670 :
671 : /**********************************************************************/
672 : /* impl StakeFlags */
673 : /**********************************************************************/
674 :
675 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/stake_flags.rs#L72
676 : #define STAKE_FLAGS_MUST_FULLY_ACTIVATE_BEFORE_DEACTIVATION_IS_PERMITTED \
677 : ( ( fd_stake_flags_t ){ .bits = 1 } )
678 :
679 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/stake_flags.rs#L75
680 837 : #define STAKE_FLAGS_EMPTY ( ( fd_stake_flags_t ){ .bits = 0 } )
681 :
682 : /**********************************************************************/
683 : /* impl Stake */
684 : /**********************************************************************/
685 :
686 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L915
687 : static int
688 : stake_split( fd_stake_t * self,
689 : ulong remaining_stake_delta,
690 : ulong split_stake_amount,
691 : uint * custom_err,
692 543 : fd_stake_t * out ) {
693 543 : if( FD_UNLIKELY( remaining_stake_delta>self->delegation.stake ) ) {
694 0 : *custom_err = FD_STAKE_ERR_INSUFFICIENT_STAKE;
695 0 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
696 0 : }
697 543 : self->delegation.stake -= remaining_stake_delta;
698 543 : fd_stake_t new;
699 543 : new = *self;
700 543 : new.delegation.stake = split_stake_amount;
701 543 : *out = new;
702 543 : return 0;
703 543 : }
704 :
705 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L934
706 : static int
707 432 : stake_deactivate( fd_stake_t * stake, ulong epoch, uint * custom_err ) {
708 432 : if( FD_UNLIKELY( stake->delegation.deactivation_epoch!=ULONG_MAX ) ) {
709 219 : *custom_err = FD_STAKE_ERR_ALREADY_DEACTIVATED;
710 219 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
711 219 : } else {
712 213 : stake->delegation.deactivation_epoch = epoch;
713 213 : return 0;
714 213 : }
715 432 : }
716 :
717 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L62
718 : static inline int
719 : new_warmup_cooldown_rate_epoch( fd_exec_instr_ctx_t const * invoke_context,
720 : /* out */ ulong * epoch,
721 3810 : int * err ) {
722 3810 : *err = 0;
723 3810 : fd_epoch_schedule_t const * epoch_schedule = fd_sysvar_cache_epoch_schedule( invoke_context->slot_ctx->sysvar_cache );
724 3810 : if( FD_UNLIKELY( !epoch_schedule ) ) {
725 0 : *epoch = ULONG_MAX;
726 0 : *err = FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
727 0 : return 1;
728 0 : }
729 3810 : ulong slot = invoke_context->epoch_ctx->features.reduce_stake_warmup_cooldown;
730 3810 : *epoch = fd_slot_to_epoch( epoch_schedule, slot, NULL );
731 3810 : return 1;
732 3810 : }
733 :
734 : /**********************************************************************/
735 : /* util */
736 : /**********************************************************************/
737 :
738 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/state.rs#L205
739 : FD_FN_CONST static inline ulong
740 0 : stake_state_v2_size_of( void ) {
741 0 : return 200;
742 0 : }
743 :
744 : /**********************************************************************/
745 : /* impl MergeKind */
746 : /**********************************************************************/
747 :
748 : static fd_stake_meta_t const *
749 2484 : meta( merge_kind_t const * self ) {
750 2484 : switch( self->discriminant ) {
751 1542 : case merge_kind_inactive:
752 1542 : return &self->inner.inactive.meta;
753 453 : case merge_kind_activation_epoch:
754 453 : return &self->inner.activation_epoch.meta;
755 489 : case merge_kind_fully_active:
756 489 : return &self->inner.fully_active.meta;
757 0 : default:
758 0 : FD_LOG_ERR( ( "invalid merge_kind_t discriminant" ) );
759 2484 : }
760 2484 : }
761 :
762 : static fd_stake_t const *
763 414 : active_stake( merge_kind_t const * self ) {
764 414 : switch( self->discriminant ) {
765 222 : case merge_kind_inactive:
766 222 : return NULL;
767 117 : case merge_kind_activation_epoch:
768 117 : return &self->inner.activation_epoch.stake;
769 75 : case merge_kind_fully_active:
770 75 : return &self->inner.fully_active.stake;
771 0 : default:
772 0 : FD_LOG_ERR( ( "invalid merge_kind_t discriminant" ) );
773 414 : }
774 414 : }
775 :
776 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1097
777 : static int
778 : get_if_mergeable( fd_exec_instr_ctx_t * invoke_context, // not const to log
779 : fd_stake_state_v2_t const * stake_state,
780 : ulong stake_lamports,
781 : fd_sol_sysvar_clock_t const * clock,
782 : fd_stake_history_t const * stake_history,
783 : merge_kind_t * out,
784 2535 : uint * custom_err ) {
785 : // stake_history must be non-NULL
786 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1104
787 2535 : switch( stake_state->discriminant ) {
788 1833 : case fd_stake_state_v2_enum_stake: {
789 1833 : fd_stake_meta_t const * meta = &stake_state->inner.stake.meta;
790 1833 : fd_stake_t const * stake = &stake_state->inner.stake.stake;
791 1833 : fd_stake_flags_t const * stake_flags = &stake_state->inner.stake.stake_flags;
792 :
793 1833 : ulong new_rate_activation_epoch = ULONG_MAX;
794 1833 : int err;
795 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1111
796 1833 : int is_some = new_warmup_cooldown_rate_epoch( invoke_context, &new_rate_activation_epoch, &err );
797 1833 : if( FD_UNLIKELY( err ) ) return err;
798 :
799 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1108
800 1833 : fd_stake_history_entry_t status =
801 1833 : stake_activating_and_deactivating( &stake->delegation,
802 1833 : clock->epoch,
803 1833 : stake_history,
804 1833 : fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) );
805 :
806 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1115
807 1833 : if( status.effective==0 && status.activating==0 && status.deactivating==0 ) {
808 :
809 594 : *out = ( merge_kind_t ){ .discriminant = merge_kind_inactive,
810 594 : .inner = { .inactive = { .meta = *meta,
811 594 : .active_stake = stake_lamports,
812 594 : .stake_flags = *stake_flags } } };
813 594 : return 0;
814 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1116
815 1239 : } else if( status.effective==0 ) {
816 342 : *out = ( merge_kind_t ){ .discriminant = merge_kind_activation_epoch,
817 342 : .inner = { .activation_epoch = { .meta = *meta,
818 342 : .stake = *stake,
819 342 : .stake_flags = *stake_flags } } };
820 342 : return 0;
821 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1117
822 897 : } else if( status.activating==0 && status.deactivating==0 ) {
823 336 : *out = ( merge_kind_t ){ .discriminant = merge_kind_fully_active,
824 336 : .inner = { .fully_active = { .meta = *meta,
825 336 : .stake = *stake } } };
826 336 : return 0;
827 561 : } else {
828 561 : fd_log_collector_msg_literal( invoke_context, "stake account with transient stake cannot be merged" );
829 561 : *custom_err = FD_STAKE_ERR_MERGE_TRANSIENT_STAKE;
830 561 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
831 561 : }
832 0 : break;
833 1833 : }
834 552 : case fd_stake_state_v2_enum_initialized: {
835 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1126
836 552 : *out = ( merge_kind_t ){ .discriminant = merge_kind_inactive,
837 552 : .inner = { .inactive = { .meta = stake_state->inner.initialized.meta,
838 552 : .active_stake = stake_lamports,
839 552 : .stake_flags = STAKE_FLAGS_EMPTY} } };
840 552 : break;
841 1833 : }
842 150 : default:
843 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1128
844 150 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
845 2535 : }
846 552 : return 0;
847 2535 : }
848 :
849 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1132
850 : static int
851 : metas_can_merge( fd_exec_instr_ctx_t * invoke_context, // not const to log
852 : fd_stake_meta_t const * stake,
853 : fd_stake_meta_t const * source,
854 : fd_sol_sysvar_clock_t const * clock,
855 660 : uint * custom_err ) {
856 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1139
857 660 : int can_merge_lockups =
858 660 : ( !memcmp( &stake->lockup, &source->lockup, sizeof( fd_stake_lockup_t ) ) ) ||
859 660 : ( !lockup_is_in_force( &stake->lockup, clock, NULL ) &&
860 327 : !lockup_is_in_force( &source->lockup, clock, NULL ) );
861 :
862 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1146
863 660 : if( FD_LIKELY( !memcmp( &stake->authorized, &source->authorized, sizeof( fd_stake_authorized_t ) ) && can_merge_lockups ) ) {
864 378 : return 0;
865 378 : } else {
866 282 : fd_log_collector_msg_literal( invoke_context, "Unable to merge due to metadata mismatch" );
867 282 : *custom_err = FD_STAKE_ERR_MERGE_MISMATCH;
868 282 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
869 282 : }
870 660 : }
871 :
872 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1154
873 : static int
874 : active_delegations_can_merge( fd_exec_instr_ctx_t * invoke_context, // not const to log
875 : fd_delegation_t const * stake,
876 : fd_delegation_t const * source,
877 51 : uint * custom_err ) {
878 51 : if( memcmp( &stake->voter_pubkey, &source->voter_pubkey, sizeof(fd_pubkey_t) ) ) {
879 3 : fd_log_collector_msg_literal( invoke_context, "Unable to merge due to voter mismatch" );
880 3 : *custom_err = FD_STAKE_ERR_MERGE_MISMATCH;
881 3 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
882 48 : } else if( FD_LIKELY( stake->deactivation_epoch==ULONG_MAX && source->deactivation_epoch==ULONG_MAX ) ) {
883 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1162
884 39 : return 0;
885 39 : } else {
886 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1167
887 9 : fd_log_collector_msg_literal( invoke_context, "Unable to merge due to stake deactivation" );
888 9 : *custom_err = FD_STAKE_ERR_MERGE_MISMATCH;
889 9 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
890 9 : }
891 51 : }
892 :
893 : static int
894 : stake_weighted_credits_observed( fd_stake_t const * stake,
895 : ulong absorbed_lamports,
896 : ulong absorbed_credits_observed,
897 60 : ulong * out ) {
898 : /* https://github.com/anza-xyz/agave/blob/dc74c22960b4f2adfc672f6dc3bfaa74ec1d5d48/programs/stake/src/stake_state.rs#L1194 */
899 60 : if( FD_LIKELY( stake->credits_observed==absorbed_credits_observed ) ) {
900 39 : *out = stake->credits_observed;
901 39 : return 1;
902 39 : } else {
903 : /* https://github.com/anza-xyz/agave/blob/dc74c22960b4f2adfc672f6dc3bfaa74ec1d5d48/programs/stake/src/stake_state.rs#L1197 */
904 : /* let total_stake = u128::from(stake.delegation.stake.checked_add(absorbed_lamports)?); */
905 21 : ulong total_stake;
906 : /* If there is an overflow on the ulong addition then exit */
907 21 : if( FD_UNLIKELY( fd_ulong_checked_add( stake->delegation.stake, absorbed_lamports, &total_stake ) ) ) {
908 6 : return 0;
909 6 : }
910 :
911 : /* https://github.com/anza-xyz/agave/blob/9489096dc5b7f0a61a981f3d0fd393d264896c2a/programs/stake/src/stake_state.rs#L1198 */
912 : /* The multiplication of two 64 bit integers will never overflow the 128 bits */
913 15 : ulong stake_weighted_credits_h;
914 15 : ulong stake_weighted_credits_l;
915 : /* let stake_weighted_credits = */
916 : /* u128::from(stake.credits_observed).checked_mul(u128::from(stake.delegation.stake))?; */
917 15 : fd_uwide_mul( &stake_weighted_credits_h, &stake_weighted_credits_l,
918 15 : stake->credits_observed, stake->delegation.stake );
919 :
920 : /* https://github.com/anza-xyz/agave/blob/9489096dc5b7f0a61a981f3d0fd393d264896c2a/programs/stake/src/stake_state.rs#L1200 */
921 : /* The multiplication of two 64 bit integers will never overflow the 128 bits */
922 15 : ulong absorbed_weighted_credits_h;
923 15 : ulong absorbed_weighted_credits_l;
924 : /* let absorbed_weighted_credits = */
925 : /* u128::from(absorbed_credits_observed).checked_mul(u128::from(absorbed_lamports))?; */
926 15 : fd_uwide_mul( &absorbed_weighted_credits_h, &absorbed_weighted_credits_l,
927 15 : absorbed_credits_observed, absorbed_lamports );
928 :
929 : /* https://github.com/anza-xyz/agave/blob/9489096dc5b7f0a61a981f3d0fd393d264896c2a/programs/stake/src/stake_state.rs#L1204 */
930 : /* let total_weighted_credits = stake_weighted_credits */
931 : /* .checked_add(absorbed_weighted_credits)? */
932 : /* .checked_add(total_stake)? */
933 : /* .checked_sub(1)?; */
934 15 : ulong total_weighted_credits_partial_one_h;
935 15 : ulong total_weighted_credits_partial_one_l;
936 15 : ulong carry_out = fd_uwide_add( &total_weighted_credits_partial_one_h, &total_weighted_credits_partial_one_l,
937 15 : stake_weighted_credits_h, stake_weighted_credits_l,
938 15 : absorbed_weighted_credits_h, absorbed_weighted_credits_l, 0UL );
939 : /* return on overflow */
940 15 : if( FD_UNLIKELY( carry_out ) ) {
941 0 : return 0;
942 0 : }
943 :
944 15 : ulong total_weighted_credits_partial_two_h;
945 15 : ulong total_weighted_credits_partial_two_l;
946 15 : carry_out = fd_uwide_add( &total_weighted_credits_partial_two_h, &total_weighted_credits_partial_two_l,
947 15 : total_weighted_credits_partial_one_h, total_weighted_credits_partial_one_l,
948 15 : 0UL, total_stake, 0UL );
949 : /* return on overflow */
950 15 : if( FD_UNLIKELY( carry_out ) ) {
951 0 : return 0;
952 0 : }
953 :
954 : /* The only way we can underflow the subtraction of 1 is if the value of total_weighted_credits_partial_two is zero */
955 15 : if( FD_UNLIKELY( total_weighted_credits_partial_two_h==0 && total_weighted_credits_partial_two_l==0 ) ) {
956 0 : return 0;
957 0 : }
958 15 : ulong total_weighted_credits_h;
959 15 : ulong total_weighted_credits_l;
960 15 : fd_uwide_dec( &total_weighted_credits_h, &total_weighted_credits_l,
961 15 : total_weighted_credits_partial_two_h, total_weighted_credits_partial_two_l, 1UL );
962 :
963 : /* https://github.com/anza-xyz/agave/blob/8a1b2dc3fa4b85e26fbce0db06a462d4853b0652/programs/stake/src/stake_state.rs#L1208 */
964 : /* u64::try_from(total_weighted_credits.checked_div(total_stake)?).ok() */
965 15 : ulong res_h;
966 15 : ulong res_l;
967 15 : if( FD_UNLIKELY( fd_uwide_div( &res_h, &res_l, total_weighted_credits_h, total_weighted_credits_l, total_stake ) ) ) {
968 0 : return 0;
969 0 : }
970 15 : *out = res_l;
971 15 : return 1;
972 15 : }
973 60 : }
974 :
975 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1239
976 : static int
977 : merge_delegation_stake_and_credits_observed( FD_FN_UNUSED fd_exec_instr_ctx_t const * invoke_context,
978 : fd_stake_t * stake,
979 : ulong absorbed_lamports,
980 60 : ulong absorbed_credits_observed ) {
981 60 : int rc;
982 60 : int is_some = stake_weighted_credits_observed(
983 60 : stake, absorbed_lamports, absorbed_credits_observed, &stake->credits_observed );
984 60 : if( FD_UNLIKELY( !is_some ) ) return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
985 54 : rc = fd_ulong_checked_add( stake->delegation.stake, absorbed_lamports, &stake->delegation.stake );
986 54 : if( FD_UNLIKELY( rc ) ) return rc;
987 51 : return 0;
988 54 : }
989 :
990 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1171
991 : static int
992 : merge_kind_merge( merge_kind_t self,
993 : fd_exec_instr_ctx_t * invoke_context, // not const to log
994 : merge_kind_t source,
995 : fd_sol_sysvar_clock_t const * clock,
996 : fd_stake_state_v2_t * out,
997 : int * is_some,
998 426 : uint * custom_err ) {
999 426 : int rc;
1000 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1177
1001 426 : rc = metas_can_merge( invoke_context, meta( &self ), meta( &source ), clock, custom_err );
1002 426 : if( FD_UNLIKELY( rc ) ) return rc;
1003 :
1004 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1178-L1188
1005 207 : fd_stake_t const * stake = active_stake( &self );
1006 207 : fd_stake_t const * source_ = active_stake( &source );
1007 :
1008 : // FIXME FD_LIKELY
1009 207 : if( stake && source_ ) {
1010 51 : rc = active_delegations_can_merge(
1011 51 : invoke_context, &stake->delegation, &source_->delegation, custom_err );
1012 51 : if( FD_UNLIKELY( rc ) ) return rc;
1013 51 : }
1014 :
1015 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1188
1016 : // FIXME FD_LIKELY
1017 195 : fd_stake_state_v2_t merged_state_ = {0};
1018 195 : fd_stake_state_v2_t * merged_state = &merged_state_;
1019 195 : if( self.discriminant==merge_kind_inactive && source.discriminant==merge_kind_inactive ) {
1020 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1189
1021 66 : merged_state = NULL;
1022 129 : } else if( self.discriminant==merge_kind_inactive && source.discriminant==merge_kind_activation_epoch ) {
1023 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1190
1024 39 : merged_state = NULL;
1025 90 : } else if( self.discriminant==merge_kind_activation_epoch && source.discriminant==merge_kind_inactive ) {
1026 42 : fd_stake_meta_t meta = self.inner.activation_epoch.meta;
1027 42 : fd_stake_t stake = self.inner.activation_epoch.stake;
1028 42 : fd_stake_flags_t stake_flags = self.inner.activation_epoch.stake_flags;
1029 42 : ulong source_lamports = source.inner.inactive.active_stake;
1030 42 : fd_stake_flags_t source_stake_flags = source.inner.inactive.stake_flags;
1031 :
1032 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1195
1033 42 : rc = fd_ulong_checked_add( stake.delegation.stake, source_lamports, &stake.delegation.stake );
1034 42 : if( FD_UNLIKELY( rc ) ) return rc;
1035 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1196
1036 39 : *merged_state = ( fd_stake_state_v2_t ){
1037 39 : .discriminant = fd_stake_state_v2_enum_stake,
1038 39 : .inner = { .stake = { .meta = meta,
1039 39 : .stake = stake,
1040 39 : .stake_flags = { .bits = stake_flags.bits | source_stake_flags.bits } } } };
1041 48 : } else if( self.discriminant==merge_kind_activation_epoch && source.discriminant==merge_kind_activation_epoch ) {
1042 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1203
1043 18 : fd_stake_meta_t meta = self.inner.activation_epoch.meta;
1044 18 : fd_stake_t stake = self.inner.activation_epoch.stake;
1045 18 : fd_stake_flags_t stake_flags = self.inner.activation_epoch.stake_flags;
1046 18 : fd_stake_meta_t source_meta = source.inner.activation_epoch.meta;
1047 18 : fd_stake_t source_stake = source.inner.activation_epoch.stake;
1048 18 : fd_stake_flags_t source_stake_flags = source.inner.activation_epoch.stake_flags;
1049 :
1050 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1206
1051 18 : ulong source_lamports = ULONG_MAX;
1052 18 : rc = fd_ulong_checked_add( source_meta.rent_exempt_reserve, source_stake.delegation.stake, &source_lamports );
1053 18 : if( FD_UNLIKELY( rc ) ) return rc;
1054 :
1055 : // // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1210
1056 18 : rc = merge_delegation_stake_and_credits_observed(invoke_context, &stake, source_lamports, source_stake.credits_observed );
1057 18 : if( FD_UNLIKELY( rc ) ) return rc;
1058 :
1059 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1215
1060 18 : *merged_state = ( fd_stake_state_v2_t ){
1061 18 : .discriminant = fd_stake_state_v2_enum_stake,
1062 18 : .inner = { .stake = { .meta = meta,
1063 18 : .stake = stake,
1064 18 : .stake_flags = { .bits = stake_flags.bits | source_stake_flags.bits } } } };
1065 30 : } else if( self.discriminant==merge_kind_fully_active && source.discriminant==merge_kind_fully_active ) {
1066 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1221
1067 21 : fd_stake_meta_t meta = self.inner.fully_active.meta;
1068 21 : fd_stake_t stake = self.inner.fully_active.stake;
1069 21 : fd_stake_t source_stake = source.inner.fully_active.stake;
1070 21 : rc = merge_delegation_stake_and_credits_observed(
1071 21 : invoke_context, &stake, source_stake.delegation.stake, source_stake.credits_observed );
1072 21 : if( FD_UNLIKELY( rc ) ) return rc;
1073 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L1231
1074 12 : *merged_state = ( fd_stake_state_v2_t ){
1075 12 : .discriminant = fd_stake_state_v2_enum_stake,
1076 12 : .inner = { .stake = { .meta = meta, .stake = stake, .stake_flags = STAKE_FLAGS_EMPTY } } };
1077 12 : } else {
1078 9 : *custom_err = FD_STAKE_ERR_MERGE_MISMATCH;
1079 9 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1080 9 : }
1081 174 : if( !merged_state ) {
1082 105 : *is_some = 0;
1083 105 : return 0;
1084 105 : }
1085 69 : *is_some = 1;
1086 69 : *out = *merged_state;
1087 69 : return 0;
1088 174 : }
1089 :
1090 : /**********************************************************************/
1091 : /* mod stake_state */
1092 : /**********************************************************************/
1093 :
1094 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L72
1095 : static int
1096 : get_stake_status( fd_exec_instr_ctx_t const * invoke_context,
1097 : fd_stake_t * stake,
1098 : fd_sol_sysvar_clock_t const * clock,
1099 1071 : fd_stake_activation_status_t * out ) {
1100 1071 : fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history( invoke_context->slot_ctx->sysvar_cache );
1101 1071 : if( FD_UNLIKELY( !stake_history ) )
1102 6 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1103 1065 : ulong new_rate_activation_epoch = ULONG_MAX;
1104 1065 : int err;
1105 1065 : int is_some = new_warmup_cooldown_rate_epoch( invoke_context, &new_rate_activation_epoch, &err );
1106 1065 : if( FD_UNLIKELY( err ) ) return err;
1107 :
1108 1065 : *out =
1109 1065 : stake_activating_and_deactivating( &stake->delegation,
1110 1065 : clock->epoch,
1111 1065 : stake_history,
1112 1065 : fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) );
1113 1065 : return 0;
1114 1065 : }
1115 :
1116 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/vote/state/mod.rs#L740
1117 : static ulong
1118 333 : get_credits( fd_vote_state_t const * vote_state ) {
1119 :
1120 333 : return ( deq_fd_vote_epoch_credits_t_empty( vote_state->epoch_credits )
1121 333 : ? 0
1122 333 : : deq_fd_vote_epoch_credits_t_peek_index(
1123 102 : vote_state->epoch_credits,
1124 102 : deq_fd_vote_epoch_credits_t_cnt( vote_state->epoch_credits ) - 1 )
1125 102 : ->credits );
1126 333 : }
1127 :
1128 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L85
1129 : static int
1130 : redelegate_stake( fd_exec_instr_ctx_t const * ctx,
1131 : fd_stake_t * stake,
1132 : ulong stake_lamports,
1133 : fd_pubkey_t const * voter_pubkey,
1134 : fd_vote_state_t const * vote_state,
1135 : fd_sol_sysvar_clock_t const * clock,
1136 : fd_stake_history_t const * stake_history,
1137 261 : uint * custom_err ) {
1138 261 : ulong new_rate_activation_epoch = ULONG_MAX;
1139 261 : int err;
1140 261 : int is_some = new_warmup_cooldown_rate_epoch( ctx, &new_rate_activation_epoch, &err );
1141 261 : if( FD_UNLIKELY( err ) ) return err;
1142 :
1143 : // FIXME FD_LIKELY
1144 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L96
1145 261 : if( delegation_stake( &stake->delegation, clock->epoch, stake_history, fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) )!=0 ) {
1146 :
1147 138 : if( FD_LIKELY( !memcmp( &stake->delegation.voter_pubkey, voter_pubkey, sizeof( fd_pubkey_t ) ) ) &&
1148 138 : clock->epoch==stake->delegation.deactivation_epoch ) {
1149 72 : stake->delegation.deactivation_epoch = ULONG_MAX;
1150 72 : return 0;
1151 72 : } else {
1152 66 : *custom_err = FD_STAKE_ERR_TOO_SOON_TO_REDELEGATE;
1153 66 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1154 66 : }
1155 138 : }
1156 :
1157 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L114-L118
1158 123 : stake->delegation.stake = stake_lamports;
1159 123 : stake->delegation.activation_epoch = clock->epoch;
1160 123 : stake->delegation.deactivation_epoch = ULONG_MAX;
1161 123 : stake->delegation.voter_pubkey = *voter_pubkey;
1162 123 : stake->credits_observed = get_credits( vote_state );
1163 123 : return 0;
1164 261 : }
1165 :
1166 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L202
1167 : static fd_stake_t
1168 : new_stake( ulong stake,
1169 : fd_pubkey_t const * voter_pubkey,
1170 : fd_vote_state_t const * vote_state,
1171 210 : ulong activation_epoch ) {
1172 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L208
1173 210 : return ( fd_stake_t ){
1174 210 : .delegation = {.voter_pubkey = *voter_pubkey,
1175 210 : .stake = stake,
1176 210 : .activation_epoch = activation_epoch,
1177 210 : .deactivation_epoch = ULONG_MAX,
1178 210 : .warmup_cooldown_rate = DEFAULT_WARMUP_COOLDOWN_RATE},
1179 210 : .credits_observed = get_credits( vote_state ),
1180 210 : };
1181 210 : }
1182 :
1183 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L214
1184 : static int
1185 : initialize( fd_exec_instr_ctx_t const * ctx,
1186 : fd_borrowed_account_t const * stake_account,
1187 : ulong stake_acc_idx,
1188 : fd_stake_authorized_t const * authorized,
1189 : fd_stake_lockup_t const * lockup,
1190 450 : fd_rent_t const * rent ) {
1191 :
1192 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L220
1193 :
1194 450 : if( FD_UNLIKELY( stake_account->const_meta->dlen!=stake_state_v2_size_of() ) )
1195 117 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1196 :
1197 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L224
1198 333 : fd_stake_state_v2_t stake_state = {0};
1199 333 : do {
1200 333 : int rc = get_state( stake_account, fd_scratch_virtual(), &stake_state );
1201 333 : if( FD_UNLIKELY( rc ) ) return rc;
1202 333 : } while(0);
1203 :
1204 327 : if( FD_LIKELY( stake_state.discriminant==fd_stake_state_v2_enum_uninitialized ) ) {
1205 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L225
1206 297 : ulong rent_exempt_reserve = fd_rent_exempt_minimum_balance( rent, stake_account->const_meta->dlen );
1207 :
1208 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L226
1209 297 : if( FD_LIKELY( stake_account->const_meta->info.lamports>=rent_exempt_reserve ) ) {
1210 243 : fd_stake_state_v2_t initialized = {
1211 243 : .discriminant = fd_stake_state_v2_enum_initialized,
1212 243 : .inner = { .initialized = { .meta = { .rent_exempt_reserve = rent_exempt_reserve,
1213 243 : .authorized = *authorized,
1214 243 : .lockup = *lockup } } } };
1215 243 : return set_state( ctx, stake_acc_idx, &initialized );
1216 243 : } else {
1217 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L233
1218 54 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1219 54 : }
1220 :
1221 297 : } else {
1222 :
1223 : /// https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L236
1224 30 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1225 :
1226 30 : }
1227 327 : }
1228 :
1229 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L243
1230 : static int
1231 : authorize( fd_exec_instr_ctx_t const * ctx,
1232 : fd_borrowed_account_t * stake_account,
1233 : ulong stake_acc_idx,
1234 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
1235 : fd_pubkey_t const * new_authority,
1236 : fd_stake_authorize_t const * stake_authorize,
1237 : fd_sol_sysvar_clock_t const * clock,
1238 : fd_pubkey_t const * custodian,
1239 921 : uint * custom_err ) {
1240 921 : int rc;
1241 921 : fd_stake_state_v2_t stake_state = {0};
1242 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L251
1243 921 : rc = get_state( stake_account, fd_scratch_virtual(), &stake_state );
1244 921 : if( FD_UNLIKELY( rc ) ) return rc;
1245 774 : switch( stake_state.discriminant ) {
1246 : /* FIXME check if the compiler can optimize away branching (given the layout of `meta` in both
1247 : * union members) and instead fallthrough */
1248 207 : case fd_stake_state_v2_enum_stake: {
1249 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L252
1250 207 : fd_stake_meta_t * meta = &stake_state.inner.stake.meta;
1251 :
1252 207 : fd_stake_lockup_custodian_args_t lockup_custodian_args = {
1253 207 : .lockup = meta->lockup, .clock = *clock, .custodian = (fd_pubkey_t *)custodian };
1254 207 : rc = authorized_authorize(
1255 207 : &meta->authorized, /* &mut self */
1256 207 : signers,
1257 207 : new_authority,
1258 207 : stake_authorize,
1259 207 : &lockup_custodian_args,
1260 207 : custom_err );
1261 207 : if( FD_UNLIKELY( rc ) ) return rc;
1262 :
1263 51 : return set_state( ctx, stake_acc_idx, &stake_state );
1264 207 : }
1265 540 : case fd_stake_state_v2_enum_initialized: {
1266 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L261
1267 540 : fd_stake_meta_t * meta = &stake_state.inner.initialized.meta;
1268 :
1269 540 : fd_stake_lockup_custodian_args_t lockup_custodian_args = {
1270 540 : .lockup = meta->lockup, .clock = *clock, .custodian = (fd_pubkey_t *)custodian };
1271 540 : rc = authorized_authorize(
1272 540 : &meta->authorized,
1273 540 : signers,
1274 540 : new_authority,
1275 540 : stake_authorize,
1276 540 : &lockup_custodian_args,
1277 540 : custom_err );
1278 540 : if( FD_UNLIKELY( rc ) ) return rc;
1279 :
1280 273 : return set_state( ctx, stake_acc_idx, &stake_state );
1281 540 : }
1282 27 : default:
1283 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L270
1284 27 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1285 774 : }
1286 0 : return rc;
1287 774 : }
1288 :
1289 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L275
1290 : static int
1291 : authorize_with_seed( fd_exec_instr_ctx_t const * ctx,
1292 : fd_borrowed_account_t * stake_account,
1293 : ulong stake_acc_idx,
1294 : uchar authority_base_index,
1295 : char const * authority_seed,
1296 : ulong authority_seed_len,
1297 : fd_pubkey_t const * authority_owner,
1298 : fd_pubkey_t const * new_authority,
1299 : fd_stake_authorize_t const * stake_authorize,
1300 : fd_sol_sysvar_clock_t const * clock,
1301 429 : fd_pubkey_t const * custodian ) {
1302 429 : int rc;
1303 429 : fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = {0};
1304 429 : fd_pubkey_t out = {0};
1305 429 : if( FD_LIKELY( fd_instr_acc_is_signer_idx( ctx->instr, authority_base_index ) ) ) {
1306 :
1307 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L289
1308 363 : fd_pubkey_t const * base_pubkey = &ctx->instr->acct_pubkeys[authority_base_index];
1309 :
1310 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L293
1311 363 : rc = fd_pubkey_create_with_seed( ctx,
1312 363 : base_pubkey->uc,
1313 363 : authority_seed,
1314 363 : authority_seed_len,
1315 363 : authority_owner->uc,
1316 363 : /* out */ out.uc );
1317 363 : if( FD_UNLIKELY( rc ) ) return rc;
1318 216 : signers[0] = &out;
1319 216 : }
1320 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L299
1321 282 : return authorize( ctx,
1322 282 : stake_account,
1323 282 : stake_acc_idx,
1324 282 : signers,
1325 282 : new_authority,
1326 282 : stake_authorize,
1327 282 : clock,
1328 282 : custodian,
1329 282 : &ctx->txn_ctx->custom_err );
1330 429 : }
1331 :
1332 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L310
1333 : static int
1334 : delegate( fd_exec_instr_ctx_t const * ctx,
1335 : uchar stake_account_index,
1336 : uchar vote_account_index,
1337 : fd_sol_sysvar_clock_t const * clock,
1338 : fd_stake_history_t const * stake_history,
1339 1272 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX] ) {
1340 1272 : int rc;
1341 :
1342 1272 : fd_valloc_t scratch_valloc = fd_scratch_virtual();
1343 :
1344 1272 : fd_pubkey_t const * vote_pubkey;
1345 1272 : fd_vote_state_versioned_t vote_state = {0};
1346 1272 : int vote_get_state_rc;
1347 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L321
1348 5088 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, vote_account_index, vote_account ) {
1349 :
1350 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L323
1351 1272 : if( FD_UNLIKELY( memcmp( &vote_account->const_meta->info.owner, fd_solana_vote_program_id.key, 32UL ) ) )
1352 39 : return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
1353 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L3326
1354 1233 : vote_pubkey = vote_account->pubkey;
1355 : // https://github.com/anza-xyz/agave/blob/a60fbc2288d626a4f1846052c8fcb98d3f9ea58d/programs/stake/src/stake_state.rs#L327
1356 1233 : vote_get_state_rc = fd_vote_get_state( vote_account, scratch_valloc, &vote_state );
1357 :
1358 1272 : } FD_BORROWED_ACCOUNT_DROP( vote_account );
1359 :
1360 1233 : fd_stake_state_v2_t stake_state = {0};
1361 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L330
1362 4932 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) {
1363 :
1364 1233 : rc = get_state( stake_account, fd_scratch_virtual(), &stake_state );
1365 1233 : if( FD_UNLIKELY( rc ) ) return rc;
1366 :
1367 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L332
1368 1083 : switch( stake_state.discriminant ) {
1369 519 : case fd_stake_state_v2_enum_initialized: {
1370 519 : fd_stake_meta_t meta = stake_state.inner.initialized.meta;
1371 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L334
1372 519 : rc = authorized_check( &meta.authorized, signers, STAKE_AUTHORIZE_STAKER );
1373 519 : if( FD_UNLIKELY( rc ) ) return rc;
1374 :
1375 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L335-L336
1376 264 : validated_delegated_info_t validated_delegated_info;
1377 264 : rc = validate_delegated_amount( stake_account,
1378 264 : &meta,
1379 264 : ctx->slot_ctx,
1380 264 : &validated_delegated_info,
1381 264 : &ctx->txn_ctx->custom_err );
1382 264 : if( FD_UNLIKELY( rc ) ) return rc;
1383 213 : ulong stake_amount = validated_delegated_info.stake_amount;
1384 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L340
1385 213 : if( FD_UNLIKELY( vote_get_state_rc ) ) return vote_get_state_rc;
1386 210 : fd_vote_convert_to_current( &vote_state, scratch_valloc ); // FIXME
1387 210 : fd_stake_t stake =
1388 210 : new_stake( stake_amount, vote_pubkey, &vote_state.inner.current, clock->epoch );
1389 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L343
1390 210 : fd_stake_state_v2_t new_stake_state = { .discriminant = fd_stake_state_v2_enum_stake,
1391 210 : .inner = { .stake = {
1392 210 : .meta = meta,
1393 210 : .stake = stake,
1394 210 : .stake_flags = STAKE_FLAGS_EMPTY } } };
1395 210 : return set_state( ctx, stake_account_index, &new_stake_state );
1396 213 : }
1397 540 : case fd_stake_state_v2_enum_stake: {
1398 540 : fd_stake_meta_t meta = stake_state.inner.stake.meta;
1399 540 : fd_stake_t stake = stake_state.inner.stake.stake;
1400 540 : fd_stake_flags_t stake_flags = stake_state.inner.stake.stake_flags;
1401 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L346
1402 540 : rc = authorized_check( &meta.authorized, signers, STAKE_AUTHORIZE_STAKER );
1403 540 : if( FD_UNLIKELY( rc ) ) return rc;
1404 :
1405 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L347-L348
1406 366 : validated_delegated_info_t validated_delegated_info;
1407 366 : rc = validate_delegated_amount( stake_account,
1408 366 : &meta,
1409 366 : ctx->slot_ctx,
1410 366 : &validated_delegated_info,
1411 366 : &ctx->txn_ctx->custom_err );
1412 366 : if( FD_UNLIKELY( rc ) ) return rc;
1413 267 : ulong stake_amount = validated_delegated_info.stake_amount;
1414 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L354
1415 267 : if( FD_UNLIKELY( vote_get_state_rc ) ) return vote_get_state_rc;
1416 261 : fd_vote_convert_to_current( &vote_state, scratch_valloc );
1417 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L349
1418 261 : rc = redelegate_stake( ctx,
1419 261 : &stake,
1420 261 : stake_amount,
1421 261 : vote_pubkey,
1422 261 : &vote_state.inner.current,
1423 261 : clock,
1424 261 : stake_history,
1425 261 : &ctx->txn_ctx->custom_err );
1426 261 : if( FD_UNLIKELY( rc ) ) return rc;
1427 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L358
1428 195 : fd_stake_state_v2_t new_stake_state = { .discriminant = fd_stake_state_v2_enum_stake,
1429 195 : .inner = { .stake = {
1430 195 : .meta = meta,
1431 195 : .stake = stake,
1432 195 : .stake_flags = stake_flags } } };
1433 :
1434 195 : return set_state( ctx, stake_account_index, &new_stake_state );
1435 261 : }
1436 24 : default:
1437 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L360
1438 24 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1439 1083 : }
1440 1233 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
1441 1233 : }
1442 :
1443 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L364
1444 : static int
1445 : deactivate( fd_exec_instr_ctx_t const * ctx,
1446 : fd_borrowed_account_t * stake_account,
1447 : ulong stake_acc_idx,
1448 : fd_sol_sysvar_clock_t const * clock,
1449 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
1450 366 : uint * custom_err ) {
1451 366 : int rc;
1452 :
1453 366 : fd_stake_state_v2_t state = {0};
1454 366 : rc = get_state( stake_account, fd_scratch_virtual(), &state );
1455 366 : if( FD_UNLIKELY( rc ) ) return rc;
1456 :
1457 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L370
1458 282 : if( state.discriminant==fd_stake_state_v2_enum_stake ) {
1459 213 : fd_stake_meta_t * meta = &state.inner.stake.meta;
1460 213 : fd_stake_t * stake = &state.inner.stake.stake;
1461 :
1462 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L371
1463 213 : rc = authorized_check( &meta->authorized, signers, STAKE_AUTHORIZE_STAKER );
1464 213 : if( FD_UNLIKELY( rc ) ) return rc;
1465 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L372
1466 168 : rc = stake_deactivate( stake, clock->epoch, custom_err );
1467 168 : if( FD_UNLIKELY( rc ) ) return rc;
1468 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L373
1469 141 : return set_state( ctx, stake_acc_idx, &state );
1470 168 : } else {
1471 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L375
1472 69 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1473 69 : }
1474 282 : }
1475 :
1476 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L379
1477 : static int
1478 : set_lockup( fd_exec_instr_ctx_t const * ctx,
1479 : fd_borrowed_account_t * stake_account,
1480 : ulong stake_acc_idx,
1481 : fd_lockup_args_t const * lockup,
1482 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX],
1483 723 : fd_sol_sysvar_clock_t const * clock ) {
1484 723 : int rc;
1485 :
1486 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L385
1487 723 : fd_stake_state_v2_t state = {0};
1488 723 : rc = get_state( stake_account, fd_scratch_virtual(), &state );
1489 723 : if( FD_UNLIKELY( rc ) ) return rc;
1490 :
1491 558 : switch( state.discriminant ) {
1492 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L386
1493 222 : case fd_stake_state_v2_enum_initialized: {
1494 222 : fd_stake_meta_t * meta = &state.inner.initialized.meta;
1495 222 : rc = set_lockup_meta( meta, lockup, signers, clock );
1496 222 : if( FD_UNLIKELY( rc ) ) return rc;
1497 48 : return set_state( ctx, stake_acc_idx, &state );
1498 222 : }
1499 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L390
1500 303 : case fd_stake_state_v2_enum_stake: {
1501 303 : fd_stake_meta_t * meta = &state.inner.stake.meta;
1502 303 : rc = set_lockup_meta( meta, lockup, signers, clock );
1503 303 : if( FD_UNLIKELY( rc ) ) return rc;
1504 69 : return set_state( ctx, stake_acc_idx, &state );
1505 303 : }
1506 33 : default:
1507 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L394
1508 33 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1509 558 : }
1510 558 : }
1511 :
1512 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L398
1513 : static int
1514 : split( fd_exec_instr_ctx_t const * ctx,
1515 : uchar stake_account_index,
1516 : ulong lamports,
1517 : uchar split_index,
1518 2781 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX] ) {
1519 2781 : int rc;
1520 :
1521 2781 : ulong split_lamport_balance = 0;
1522 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L407
1523 11124 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, split_index, split ) {
1524 :
1525 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L409
1526 2781 : if( FD_UNLIKELY( memcmp( &split->const_meta->info.owner, fd_solana_stake_program_id.key, 32UL ) ) )
1527 81 : return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
1528 :
1529 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L412
1530 2700 : if( FD_UNLIKELY( split->const_meta->dlen!=stake_state_v2_size_of() ) )
1531 336 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1532 :
1533 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L415
1534 2364 : fd_stake_state_v2_t split_get_state = {0};
1535 2364 : rc = get_state( split, fd_scratch_virtual(), &split_get_state );
1536 2364 : if( FD_UNLIKELY( rc ) ) return rc;
1537 2361 : if( FD_UNLIKELY( split_get_state.discriminant!=fd_stake_state_v2_enum_uninitialized ) ) {
1538 75 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1539 75 : }
1540 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L418
1541 2286 : split_lamport_balance = split->const_meta->info.lamports;
1542 :
1543 2781 : } FD_BORROWED_ACCOUNT_DROP( split );
1544 :
1545 2286 : fd_stake_state_v2_t stake_state = {0};
1546 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L420
1547 9144 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account) {
1548 :
1549 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L422
1550 2286 : if( FD_UNLIKELY( lamports>stake_account->const_meta->info.lamports ) )
1551 351 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
1552 :
1553 1935 : rc = get_state( stake_account, fd_scratch_virtual(), &stake_state );
1554 1935 : if( FD_UNLIKELY( rc ) ) return rc;
1555 :
1556 2286 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
1557 :
1558 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L428
1559 1893 : switch( stake_state.discriminant ) {
1560 1128 : case fd_stake_state_v2_enum_stake: {
1561 1128 : fd_stake_meta_t * meta = &stake_state.inner.stake.meta;
1562 1128 : fd_stake_t * stake = &stake_state.inner.stake.stake;
1563 1128 : fd_stake_flags_t * stake_flags = &stake_state.inner.stake.stake_flags;
1564 :
1565 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L430
1566 1128 : rc = authorized_check( &meta->authorized, signers, STAKE_AUTHORIZE_STAKER );
1567 1128 : if( FD_UNLIKELY( rc ) ) return rc;
1568 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L431
1569 1071 : ulong minimum_delegation = get_minimum_delegation( ctx->slot_ctx );
1570 :
1571 1071 : int is_active;
1572 1071 : if( FD_UNLIKELY( FD_FEATURE_ACTIVE( ctx->slot_ctx,
1573 1071 : require_rent_exempt_split_destination ) ) ) {
1574 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L434
1575 1071 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
1576 1071 : if( FD_UNLIKELY( !clock ) )
1577 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1578 :
1579 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L435
1580 1071 : fd_stake_activation_status_t status = {0};
1581 1071 : rc = get_stake_status( ctx, stake, clock, &status );
1582 1071 : if( FD_UNLIKELY( rc ) ) return rc;
1583 :
1584 1065 : is_active = status.effective>0;
1585 1065 : } else {
1586 0 : is_active = 0;
1587 0 : }
1588 :
1589 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L438
1590 1065 : validated_split_info_t validated_split_info = {0};
1591 1065 : rc = validate_split_amount( ctx,
1592 1065 : stake_account_index,
1593 1065 : split_index,
1594 1065 : lamports,
1595 1065 : meta,
1596 1065 : minimum_delegation,
1597 1065 : is_active,
1598 1065 : &validated_split_info );
1599 1065 : if( FD_UNLIKELY( rc ) ) return rc;
1600 :
1601 606 : ulong remaining_stake_delta;
1602 606 : ulong split_stake_amount;
1603 : // FIXME FD_LIKELY
1604 :
1605 606 : if( validated_split_info.source_remaining_balance==0 ) {
1606 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L456
1607 249 : remaining_stake_delta = fd_ulong_sat_sub( lamports, meta->rent_exempt_reserve );
1608 249 : split_stake_amount = remaining_stake_delta;
1609 357 : } else {
1610 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L469
1611 357 : if( FD_UNLIKELY( fd_ulong_sat_sub( stake->delegation.stake, lamports ) <
1612 357 : minimum_delegation ) ) {
1613 36 : ctx->txn_ctx->custom_err = FD_STAKE_ERR_INSUFFICIENT_DELEGATION;
1614 36 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1615 36 : }
1616 :
1617 321 : remaining_stake_delta = lamports;
1618 321 : split_stake_amount =
1619 321 : fd_ulong_sat_sub( lamports,
1620 321 : fd_ulong_sat_sub( validated_split_info.destination_rent_exempt_reserve,
1621 321 : split_lamport_balance )
1622 :
1623 321 : );
1624 321 : }
1625 :
1626 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L487
1627 570 : if( FD_UNLIKELY( split_stake_amount<minimum_delegation ) ) {
1628 27 : ctx->txn_ctx->custom_err = FD_STAKE_ERR_INSUFFICIENT_DELEGATION;
1629 27 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1630 27 : }
1631 :
1632 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L491-L493
1633 543 : fd_stake_t split_stake = {0};
1634 543 : rc = stake_split( stake,
1635 543 : remaining_stake_delta,
1636 543 : split_stake_amount,
1637 543 : &ctx->txn_ctx->custom_err,
1638 543 : &split_stake );
1639 543 : if( FD_UNLIKELY( rc ) ) return rc;
1640 543 : fd_stake_meta_t split_meta = *meta;
1641 543 : split_meta.rent_exempt_reserve = validated_split_info.destination_rent_exempt_reserve;
1642 :
1643 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L495
1644 2172 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) {
1645 :
1646 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L497
1647 543 : rc = set_state( ctx, stake_account_index, &stake_state );
1648 543 : if( FD_UNLIKELY( rc ) ) return rc;
1649 :
1650 543 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
1651 :
1652 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L499
1653 2124 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, split_index, split ) {
1654 :
1655 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L501
1656 531 : fd_stake_state_v2_t temp = { .discriminant = fd_stake_state_v2_enum_stake,
1657 531 : .inner = { .stake = { .meta = split_meta,
1658 531 : .stake = split_stake,
1659 531 : .stake_flags = *stake_flags } } };
1660 531 : rc = set_state( ctx, split_index, &temp );
1661 531 : if( FD_UNLIKELY( rc ) ) return rc;
1662 :
1663 531 : } FD_BORROWED_ACCOUNT_DROP( split );
1664 522 : break;
1665 531 : }
1666 540 : case fd_stake_state_v2_enum_initialized: {
1667 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L504
1668 540 : fd_stake_meta_t * meta = &stake_state.inner.initialized.meta;
1669 540 : rc = authorized_check( &meta->authorized, signers, STAKE_AUTHORIZE_STAKER );
1670 540 : if( FD_UNLIKELY( rc ) ) return rc;
1671 :
1672 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L505
1673 465 : validated_split_info_t validated_split_info = {0};
1674 465 : rc = validate_split_amount( ctx,
1675 465 : stake_account_index,
1676 465 : split_index,
1677 465 : lamports,
1678 465 : meta,
1679 465 : 0,
1680 465 : 0,
1681 465 : &validated_split_info );
1682 465 : if( FD_UNLIKELY( rc ) ) return rc;
1683 :
1684 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L516
1685 318 : fd_stake_meta_t split_meta = *meta;
1686 318 : split_meta.rent_exempt_reserve = validated_split_info.destination_rent_exempt_reserve;
1687 :
1688 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L518
1689 1272 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, split_index, split ) {
1690 :
1691 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L520
1692 318 : fd_stake_state_v2_t temp = { .discriminant = fd_stake_state_v2_enum_initialized,
1693 318 : .inner = { .initialized = { .meta = split_meta } } };
1694 318 : rc = set_state( ctx, split_index, &temp );
1695 318 : if( FD_UNLIKELY( rc ) ) return rc;
1696 :
1697 318 : } FD_BORROWED_ACCOUNT_DROP( split );
1698 315 : break;
1699 318 : }
1700 315 : case fd_stake_state_v2_enum_uninitialized: {
1701 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L523
1702 222 : fd_pubkey_t const * stake_pubkey = &ctx->instr->acct_pubkeys[stake_account_index];
1703 222 : if( FD_UNLIKELY( !fd_instr_signers_contains( signers, stake_pubkey ) ) ) {
1704 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L527
1705 69 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
1706 69 : }
1707 153 : break;
1708 222 : }
1709 153 : default:
1710 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L531
1711 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1712 1893 : }
1713 :
1714 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L535
1715 3960 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) {
1716 :
1717 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L537
1718 990 : if( FD_UNLIKELY( lamports==stake_account->const_meta->info.lamports ) ) {
1719 411 : fd_stake_state_v2_t uninitialized = {0};
1720 411 : uninitialized.discriminant = fd_stake_state_v2_enum_uninitialized;
1721 411 : rc = set_state( ctx, stake_account_index, &uninitialized );
1722 411 : if( FD_UNLIKELY( rc ) ) return rc;
1723 987 : };
1724 :
1725 990 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
1726 :
1727 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L542
1728 3948 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, split_index, split ) {
1729 :
1730 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L544
1731 987 : rc = fd_account_checked_add_lamports( ctx, split_index, lamports );
1732 987 : if( FD_UNLIKELY( rc ) ) return rc;
1733 :
1734 :
1735 987 : } FD_BORROWED_ACCOUNT_DROP( split );
1736 :
1737 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L546
1738 3804 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) {
1739 :
1740 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L548
1741 951 : rc = fd_account_checked_sub_lamports( ctx, stake_account_index, lamports );
1742 951 : if( FD_UNLIKELY( rc ) ) return rc;
1743 :
1744 951 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
1745 939 : return 0;
1746 951 : }
1747 :
1748 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L552
1749 : static int
1750 : merge( fd_exec_instr_ctx_t * ctx, // not const to log
1751 : uchar stake_account_index,
1752 : uchar source_account_index,
1753 : fd_sol_sysvar_clock_t const * clock,
1754 : fd_stake_history_t const * stake_history,
1755 1635 : fd_pubkey_t const * signers[static FD_TXN_SIG_MAX] ) {
1756 1635 : int rc;
1757 :
1758 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L562
1759 6540 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, source_account_index, source_account ) {
1760 :
1761 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L565
1762 1635 : if( FD_UNLIKELY( memcmp( &source_account->const_meta->info.owner, fd_solana_stake_program_id.key, 32UL ) ) )
1763 42 : return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
1764 :
1765 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L569
1766 1593 : if( FD_UNLIKELY( !memcmp( &ctx->instr->acct_pubkeys[stake_account_index], &ctx->instr->acct_pubkeys[source_account_index], sizeof(fd_pubkey_t) ) ) )
1767 24 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
1768 :
1769 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L575
1770 6276 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) {
1771 :
1772 1569 : fd_stake_state_v2_t stake_account_state = {0};
1773 1569 : rc = get_state( stake_account, fd_scratch_virtual(), &stake_account_state );
1774 1569 : if( FD_UNLIKELY( rc ) ) return rc;
1775 :
1776 1479 : merge_kind_t stake_merge_kind = {0};
1777 1479 : fd_log_collector_msg_literal( ctx, "Checking if destination stake is mergeable" );
1778 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L579
1779 1479 : rc = get_if_mergeable( ctx,
1780 1479 : &stake_account_state,
1781 1479 : stake_account->const_meta->info.lamports,
1782 1479 : clock,
1783 1479 : stake_history,
1784 1479 : &stake_merge_kind,
1785 1479 : &ctx->txn_ctx->custom_err );
1786 1479 : if( FD_UNLIKELY( rc ) )
1787 579 : return rc;
1788 :
1789 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L588
1790 900 : rc = authorized_check( &meta( &stake_merge_kind )->authorized, signers, STAKE_AUTHORIZE_STAKER );
1791 900 : if( FD_UNLIKELY( rc ) )
1792 327 : return rc;
1793 :
1794 573 : fd_stake_state_v2_t source_account_state = {0};
1795 573 : rc = get_state( source_account, fd_scratch_virtual(), &source_account_state );
1796 573 : if( FD_UNLIKELY( rc ) ) return rc;
1797 :
1798 543 : merge_kind_t source_merge_kind = {0};
1799 543 : fd_log_collector_msg_literal( ctx, "Checking if source stake is mergeable" );
1800 : //https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L594
1801 543 : rc = get_if_mergeable( ctx,
1802 543 : &source_account_state,
1803 543 : source_account->const_meta->info.lamports,
1804 543 : clock,
1805 543 : stake_history,
1806 543 : &source_merge_kind,
1807 543 : &ctx->txn_ctx->custom_err );
1808 543 : if( FD_UNLIKELY( rc ) ) return rc;
1809 :
1810 426 : fd_stake_state_v2_t merged_state = {0};
1811 426 : int is_some = 0;
1812 426 : fd_log_collector_msg_literal( ctx, "Merging stake accounts" );
1813 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L603
1814 426 : rc = merge_kind_merge( stake_merge_kind,
1815 426 : ctx,
1816 426 : source_merge_kind,
1817 426 : clock,
1818 426 : &merged_state,
1819 426 : &is_some,
1820 426 : &ctx->txn_ctx->custom_err );
1821 426 : if( FD_UNLIKELY( rc ) ) return rc;
1822 174 : if( is_some ) {
1823 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L608
1824 69 : rc = set_state( ctx, stake_account_index, &merged_state );
1825 69 : if( FD_UNLIKELY( rc ) ) return rc;
1826 69 : }
1827 :
1828 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L608
1829 171 : fd_stake_state_v2_t uninitialized = {0};
1830 171 : uninitialized.discriminant = fd_stake_state_v2_enum_uninitialized;
1831 171 : rc = set_state( ctx, source_account_index, &uninitialized );
1832 171 : if( FD_UNLIKELY( rc ) ) return rc;
1833 :
1834 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L611-L613
1835 141 : ulong lamports = source_account->const_meta->info.lamports;
1836 141 : rc = fd_account_checked_sub_lamports( ctx, source_account_index, lamports );
1837 141 : if( FD_UNLIKELY( rc ) ) return rc;
1838 141 : rc = fd_account_checked_add_lamports( ctx, stake_account_index, lamports );
1839 141 : if( FD_UNLIKELY( rc ) ) return rc;
1840 :
1841 1569 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
1842 1635 : } FD_BORROWED_ACCOUNT_DROP( source_account );
1843 :
1844 135 : return 0;
1845 1635 : }
1846 :
1847 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L136
1848 : static int
1849 : move_stake_or_lamports_shared_checks( fd_exec_instr_ctx_t * invoke_context, // not const to log
1850 : fd_borrowed_account_t * source_account,
1851 : ulong lamports,
1852 : fd_borrowed_account_t * destination_account,
1853 : ulong stake_authority_index,
1854 : merge_kind_t * source_merge_kind,
1855 : merge_kind_t * destination_merge_kind,
1856 768 : uint * custom_err ) {
1857 768 : int rc;
1858 :
1859 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L145-L153
1860 768 : if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( invoke_context->instr, stake_authority_index ) ) ) {
1861 300 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
1862 300 : }
1863 :
1864 468 : fd_pubkey_t const * stake_authority_pubkey = &invoke_context->instr->acct_pubkeys[stake_authority_index];
1865 468 : fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = { stake_authority_pubkey };
1866 :
1867 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L158
1868 468 : if( FD_UNLIKELY( memcmp( &source_account->const_meta->info.owner, fd_solana_stake_program_id.key, sizeof(fd_pubkey_t) ) ||
1869 468 : memcmp( &destination_account->const_meta->info.owner, fd_solana_stake_program_id.key, sizeof(fd_pubkey_t) ) ) )
1870 9 : return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
1871 :
1872 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L163
1873 459 : if( FD_UNLIKELY( !memcmp( &source_account->pubkey, &destination_account->pubkey, sizeof(fd_pubkey_t) ) ) )
1874 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
1875 :
1876 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L168
1877 459 : if( FD_UNLIKELY( !fd_instr_acc_is_writable( invoke_context->instr, source_account->pubkey ) ||
1878 459 : !fd_instr_acc_is_writable( invoke_context->instr, destination_account->pubkey ) ) )
1879 174 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
1880 :
1881 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L173
1882 285 : if( lamports==0 )
1883 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
1884 :
1885 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L177-L180
1886 282 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( invoke_context->slot_ctx->sysvar_cache );
1887 282 : if( FD_UNLIKELY( !clock ) )
1888 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1889 :
1890 282 : fd_stake_history_t const * stake_history = fd_sysvar_cache_stake_history( invoke_context->slot_ctx->sysvar_cache );
1891 282 : if( FD_UNLIKELY( !stake_history ) )
1892 3 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
1893 :
1894 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L182
1895 279 : fd_stake_state_v2_t source_account_state = {0};
1896 279 : rc = get_state( source_account, fd_scratch_virtual(), &source_account_state );
1897 279 : if( FD_UNLIKELY( rc ) ) return rc;
1898 :
1899 267 : rc = get_if_mergeable( invoke_context,
1900 267 : &source_account_state,
1901 267 : source_account->const_meta->info.lamports,
1902 267 : clock,
1903 267 : stake_history,
1904 267 : source_merge_kind,
1905 267 : &invoke_context->txn_ctx->custom_err );
1906 267 : if( FD_UNLIKELY( rc ) ) return rc;
1907 :
1908 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L191
1909 264 : rc = authorized_check( &meta( source_merge_kind )->authorized, signers, STAKE_AUTHORIZE_STAKER );
1910 264 : if( FD_UNLIKELY( rc ) ) return rc;
1911 :
1912 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L197
1913 261 : fd_stake_state_v2_t destination_account_state = {0};
1914 261 : rc = get_state( destination_account, fd_scratch_virtual(), &destination_account_state );
1915 261 : if( FD_UNLIKELY( rc ) ) return rc;
1916 :
1917 246 : rc = get_if_mergeable( invoke_context,
1918 246 : &destination_account_state,
1919 246 : destination_account->const_meta->info.lamports,
1920 246 : clock,
1921 246 : stake_history,
1922 246 : destination_merge_kind,
1923 246 : &invoke_context->txn_ctx->custom_err );
1924 246 : if( FD_UNLIKELY( rc ) ) return rc;
1925 :
1926 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L206
1927 234 : rc = metas_can_merge( invoke_context, meta( source_merge_kind ), meta( destination_merge_kind ), clock, custom_err );
1928 234 : if( FD_UNLIKELY( rc ) ) return rc;
1929 :
1930 171 : return 0;
1931 234 : }
1932 :
1933 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L789
1934 : static int
1935 : move_stake(fd_exec_instr_ctx_t * ctx, // not const to log
1936 : ulong source_account_index,
1937 : ulong lamports,
1938 : ulong destination_account_index,
1939 : ulong stake_authority_index,
1940 477 : uint * custom_err ) {
1941 477 : int rc;
1942 :
1943 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L798-L804
1944 1908 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, source_account_index, source_account ) {
1945 1908 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, destination_account_index, destination_account ) {
1946 :
1947 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L804
1948 477 : merge_kind_t source_merge_kind = {0};
1949 477 : merge_kind_t destination_merge_kind = {0};
1950 477 : rc = move_stake_or_lamports_shared_checks( ctx,
1951 477 : source_account,
1952 477 : lamports,
1953 477 : destination_account,
1954 477 : stake_authority_index,
1955 477 : &source_merge_kind,
1956 477 : &destination_merge_kind,
1957 477 : &ctx->txn_ctx->custom_err );
1958 477 : if( FD_UNLIKELY( rc ) ) return rc;
1959 :
1960 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L816
1961 72 : if( FD_UNLIKELY( source_account->const_meta->dlen!=stake_state_v2_size_of() ||
1962 72 : destination_account->const_meta->dlen!=stake_state_v2_size_of() ) )
1963 6 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1964 :
1965 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L823
1966 66 : if( source_merge_kind.discriminant!=merge_kind_fully_active )
1967 6 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
1968 60 : fd_stake_meta_t * source_meta = &source_merge_kind.inner.fully_active.meta;
1969 60 : fd_stake_t * source_stake = &source_merge_kind.inner.fully_active.stake;
1970 :
1971 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L827
1972 60 : ulong minimum_delegation = get_minimum_delegation( ctx->slot_ctx );
1973 :
1974 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L831
1975 60 : if( FD_UNLIKELY( source_stake->delegation.stake<lamports ) )
1976 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
1977 :
1978 57 : ulong source_final_stake = source_stake->delegation.stake - lamports;
1979 :
1980 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L836
1981 57 : if( FD_UNLIKELY( source_final_stake!=0 && source_final_stake<minimum_delegation ) )
1982 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
1983 :
1984 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L841
1985 54 : fd_stake_meta_t * destination_meta = NULL;
1986 54 : switch( destination_merge_kind.discriminant ) {
1987 27 : case merge_kind_fully_active: {
1988 27 : fd_stake_t * destination_stake = &destination_merge_kind.inner.fully_active.stake;
1989 :
1990 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L844
1991 27 : if( FD_UNLIKELY( memcmp( &source_stake->delegation.voter_pubkey, &destination_stake->delegation.voter_pubkey, sizeof(fd_pubkey_t) ) ) ) {
1992 3 : *custom_err = FD_STAKE_ERR_VOTE_ADDRESS_MISMATCH;
1993 3 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
1994 3 : }
1995 :
1996 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L848
1997 24 : ulong destination_effective_stake = 0;
1998 24 : rc = fd_ulong_checked_add( destination_stake->delegation.stake, lamports, &destination_effective_stake );
1999 24 : if( FD_UNLIKELY( rc ) ) return FD_EXECUTOR_INSTR_ERR_ARITHMETIC_OVERFLOW;
2000 :
2001 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L855
2002 21 : if( FD_UNLIKELY( destination_effective_stake<minimum_delegation ) ) {
2003 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
2004 0 : }
2005 :
2006 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L859
2007 21 : rc = merge_delegation_stake_and_credits_observed(
2008 21 : ctx, destination_stake, lamports, source_stake->credits_observed );
2009 21 : if( FD_UNLIKELY( rc ) ) return rc;
2010 21 : destination_meta = &destination_merge_kind.inner.fully_active.meta;
2011 :
2012 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L867
2013 21 : fd_stake_state_v2_t new_destination_state = {
2014 21 : .discriminant = fd_stake_state_v2_enum_stake,
2015 21 : .inner = { .stake = {
2016 21 : .meta = *destination_meta,
2017 21 : .stake = *destination_stake,
2018 21 : .stake_flags = STAKE_FLAGS_EMPTY} } };
2019 21 : rc = set_state( ctx, destination_account_index, &new_destination_state );
2020 21 : if( FD_UNLIKELY( rc ) ) return rc;
2021 :
2022 18 : break;
2023 21 : }
2024 24 : case merge_kind_inactive: {
2025 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L877
2026 24 : if( lamports<minimum_delegation ) {
2027 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
2028 0 : }
2029 :
2030 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L881
2031 24 : fd_stake_t * destination_stake = source_stake;
2032 24 : destination_stake->delegation.stake = lamports;
2033 :
2034 24 : destination_meta = &destination_merge_kind.inner.inactive.meta;
2035 :
2036 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L886
2037 24 : fd_stake_state_v2_t new_destination_state = {
2038 24 : .discriminant = fd_stake_state_v2_enum_stake,
2039 24 : .inner = { .stake = {
2040 24 : .meta = *destination_meta,
2041 24 : .stake = *destination_stake,
2042 24 : .stake_flags = STAKE_FLAGS_EMPTY} } };
2043 24 : rc = set_state( ctx, destination_account_index, &new_destination_state );
2044 24 : if( FD_UNLIKELY( rc ) ) return rc;
2045 21 : break;
2046 24 : }
2047 21 : default:
2048 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L894
2049 3 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
2050 54 : }
2051 :
2052 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L897-L910
2053 39 : if( source_final_stake==0) {
2054 21 : fd_stake_state_v2_t new_source_state = { .discriminant = fd_stake_state_v2_enum_initialized,
2055 21 : .inner = { .initialized = { .meta = *source_meta} } };
2056 21 : rc = set_state( ctx, source_account_index, &new_source_state );
2057 21 : if( FD_UNLIKELY( rc ) ) return rc;
2058 :
2059 21 : } else {
2060 18 : source_stake->delegation.stake = source_final_stake;
2061 :
2062 18 : fd_stake_state_v2_t new_source_state = { .discriminant = fd_stake_state_v2_enum_stake,
2063 18 : .inner = { .stake = { .meta = *source_meta,
2064 18 : .stake = *source_stake,
2065 18 : .stake_flags = STAKE_FLAGS_EMPTY } } };
2066 18 : rc = set_state( ctx, source_account_index, &new_source_state );
2067 18 : if( FD_UNLIKELY( rc ) ) return rc;
2068 18 : }
2069 :
2070 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L911-L914
2071 33 : rc = fd_account_checked_sub_lamports( ctx, source_account_index, lamports );
2072 33 : if( FD_UNLIKELY( rc ) ) return rc;
2073 30 : rc = fd_account_checked_add_lamports( ctx, destination_account_index, lamports );
2074 30 : if( FD_UNLIKELY( rc ) ) return rc;
2075 :
2076 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L915-L923
2077 18 : if( FD_UNLIKELY( fd_account_get_lamports2( ctx, source_account_index )<source_meta->rent_exempt_reserve ) ||
2078 18 : fd_account_get_lamports2( ctx, destination_account_index )<destination_meta->rent_exempt_reserve ) {
2079 12 : fd_log_collector_msg_literal( ctx, "Delegation calculations violated lamport balance assumptions" );
2080 12 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
2081 12 : }
2082 :
2083 477 : } FD_BORROWED_ACCOUNT_DROP( destination_account );
2084 477 : } FD_BORROWED_ACCOUNT_DROP( source_account );
2085 :
2086 6 : return FD_EXECUTOR_INSTR_SUCCESS;
2087 477 : }
2088 :
2089 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L928
2090 : static int
2091 : move_lamports(fd_exec_instr_ctx_t * ctx, // not const to log
2092 : ulong source_account_index,
2093 : ulong lamports,
2094 : ulong destination_account_index,
2095 291 : ulong stake_authority_index ) {
2096 291 : int rc;
2097 :
2098 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L937-L942
2099 1164 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, source_account_index, source_account ) {
2100 1164 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, destination_account_index, destination_account ) {
2101 :
2102 :
2103 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L943
2104 291 : merge_kind_t source_merge_kind = {0};
2105 291 : merge_kind_t destination_merge_kind = {0};
2106 291 : rc = move_stake_or_lamports_shared_checks( ctx,
2107 291 : source_account,
2108 291 : lamports,
2109 291 : destination_account,
2110 291 : stake_authority_index,
2111 291 : &source_merge_kind,
2112 291 : &destination_merge_kind,
2113 291 : &ctx->txn_ctx->custom_err );
2114 291 : if( FD_UNLIKELY( rc ) ) return rc;
2115 :
2116 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L953-L963
2117 99 : ulong source_free_lamports;
2118 99 : switch( source_merge_kind.discriminant ) {
2119 21 : case merge_kind_fully_active: {
2120 21 : source_free_lamports = fd_ulong_sat_sub( fd_ulong_sat_sub( source_account->const_meta->info.lamports,
2121 21 : source_merge_kind.inner.fully_active.stake.delegation.stake ),
2122 21 : source_merge_kind.inner.fully_active.meta.rent_exempt_reserve );
2123 :
2124 21 : break;
2125 0 : }
2126 72 : case merge_kind_inactive: {
2127 72 : source_free_lamports = fd_ulong_sat_sub( source_merge_kind.inner.inactive.active_stake,
2128 72 : source_merge_kind.inner.inactive.meta.rent_exempt_reserve );
2129 72 : break;
2130 0 : }
2131 6 : default:
2132 6 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
2133 99 : }
2134 :
2135 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L964
2136 93 : if( FD_UNLIKELY( lamports>source_free_lamports ) ) {
2137 51 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
2138 51 : }
2139 :
2140 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_state.rs#L968-L970
2141 42 : rc = fd_account_checked_sub_lamports( ctx, source_account_index, lamports );
2142 42 : if( FD_UNLIKELY( rc ) ) return rc;
2143 :
2144 39 : rc = fd_account_checked_add_lamports( ctx, destination_account_index, lamports );
2145 39 : if( FD_UNLIKELY( rc ) ) return rc;
2146 :
2147 291 : } FD_BORROWED_ACCOUNT_DROP( destination_account );
2148 291 : } FD_BORROWED_ACCOUNT_DROP( source_account );
2149 :
2150 30 : return FD_EXECUTOR_INSTR_SUCCESS;
2151 291 : }
2152 :
2153 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L797
2154 : static int
2155 : withdraw( fd_exec_instr_ctx_t const * ctx,
2156 : uchar stake_account_index,
2157 : ulong lamports,
2158 : uchar to_index,
2159 : fd_sol_sysvar_clock_t const * clock,
2160 : fd_stake_history_t const * stake_history,
2161 : uchar withdraw_authority_index,
2162 : uchar * custodian_index,
2163 651 : ulong * new_rate_activation_epoch ) {
2164 :
2165 651 : int rc;
2166 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L809
2167 651 : fd_pubkey_t const * withdraw_authority_pubkey = &ctx->instr->acct_pubkeys[withdraw_authority_index];
2168 :
2169 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L813
2170 651 : int is_signer = fd_instr_acc_is_signer_idx( ctx->instr, withdraw_authority_index );
2171 651 : if( FD_UNLIKELY( !is_signer ) ) return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2172 :
2173 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L817
2174 576 : fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = { withdraw_authority_pubkey };
2175 :
2176 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L819
2177 2304 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, stake_account_index, stake_account ) {
2178 :
2179 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L821
2180 576 : fd_stake_state_v2_t stake_state = {0};
2181 576 : rc = get_state( stake_account, fd_scratch_virtual(), &stake_state );
2182 576 : if( FD_UNLIKELY( rc ) ) return rc;
2183 :
2184 552 : fd_stake_lockup_t lockup;
2185 552 : ulong reserve;
2186 552 : int is_staked;
2187 :
2188 552 : switch( stake_state.discriminant ) {
2189 213 : case fd_stake_state_v2_enum_stake: {
2190 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L822
2191 213 : fd_stake_meta_t * meta = &stake_state.inner.stake.meta;
2192 213 : fd_stake_t * stake = &stake_state.inner.stake.stake;
2193 :
2194 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L823
2195 213 : rc = authorized_check( &meta->authorized, signers, STAKE_AUTHORIZE_WITHDRAWER );
2196 213 : if( FD_UNLIKELY( rc ) ) return rc;
2197 :
2198 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L826
2199 183 : ulong staked = fd_ulong_if(
2200 183 : clock->epoch>=stake->delegation.deactivation_epoch,
2201 183 : delegation_stake(
2202 183 : &stake->delegation, clock->epoch, stake_history, new_rate_activation_epoch ),
2203 183 : stake->delegation.stake );
2204 :
2205 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L837
2206 183 : ulong staked_and_reserve = ULONG_MAX;
2207 183 : rc = fd_ulong_checked_add( staked, meta->rent_exempt_reserve, &staked_and_reserve );
2208 183 : if( FD_UNLIKELY( rc ) ) return rc;
2209 :
2210 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L838
2211 180 : lockup = meta->lockup;
2212 180 : reserve = staked_and_reserve;
2213 180 : is_staked = staked!=0;
2214 180 : break;
2215 183 : }
2216 264 : case fd_stake_state_v2_enum_initialized: {
2217 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L840
2218 264 : fd_stake_meta_t * meta = &stake_state.inner.initialized.meta;
2219 :
2220 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L841
2221 264 : rc = authorized_check( &meta->authorized, signers, STAKE_AUTHORIZE_WITHDRAWER );
2222 264 : if( FD_UNLIKELY( rc ) ) return rc;
2223 :
2224 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L844
2225 228 : lockup = meta->lockup;
2226 228 : reserve = meta->rent_exempt_reserve;
2227 228 : is_staked = 0;
2228 228 : break;
2229 264 : }
2230 54 : case fd_stake_state_v2_enum_uninitialized: {
2231 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L846
2232 54 : if( FD_UNLIKELY( !fd_instr_signers_contains( signers, stake_account->pubkey ) ) ) {
2233 36 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2234 36 : }
2235 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L850
2236 18 : memset( &lockup, 0, sizeof( fd_stake_lockup_t ) ); /* Lockup::default(); */
2237 18 : reserve = 0;
2238 18 : is_staked = 0;
2239 18 : break;
2240 54 : }
2241 21 : default:
2242 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L852
2243 21 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
2244 552 : }
2245 :
2246 : // FIXME FD_LIKELY
2247 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L857-L871
2248 426 : fd_pubkey_t custodian_pubkey_ = {0};
2249 426 : fd_pubkey_t const * custodian_pubkey = &custodian_pubkey_;
2250 426 : if( custodian_index ) {
2251 75 : int is_signer = fd_instr_acc_is_signer_idx( ctx->instr, *custodian_index );
2252 75 : if( is_signer ) {
2253 57 : custodian_pubkey = &ctx->instr->acct_pubkeys[*custodian_index];
2254 57 : } else {
2255 18 : custodian_pubkey = NULL;
2256 18 : }
2257 351 : } else {
2258 351 : custodian_pubkey = NULL;
2259 351 : }
2260 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L871
2261 426 : if( FD_UNLIKELY( lockup_is_in_force( &lockup, clock, custodian_pubkey ) ) ) {
2262 33 : ctx->txn_ctx->custom_err = FD_STAKE_ERR_LOCKUP_IN_FORCE;
2263 33 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
2264 393 : };
2265 :
2266 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L875
2267 393 : ulong lamports_and_reserve = ULONG_MAX;
2268 393 : rc = fd_ulong_checked_add( lamports, reserve, &lamports_and_reserve );
2269 393 : if( FD_UNLIKELY( rc ) ) return rc;
2270 :
2271 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L877
2272 369 : if( FD_UNLIKELY( is_staked && lamports_and_reserve>stake_account->const_meta->info.lamports ) ) {
2273 57 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
2274 57 : }
2275 :
2276 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L883
2277 312 : if( FD_UNLIKELY( lamports!=stake_account->const_meta->info.lamports &&
2278 312 : lamports_and_reserve>stake_account->const_meta->info.lamports ) ) {
2279 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L886
2280 75 : FD_TEST( !is_staked );
2281 75 : return FD_EXECUTOR_INSTR_ERR_INSUFFICIENT_FUNDS;
2282 75 : }
2283 :
2284 : // FIXME FD_LIKELY
2285 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L891
2286 237 : if( lamports==stake_account->const_meta->info.lamports ) {
2287 126 : fd_stake_state_v2_t uninitialized = {0};
2288 126 : uninitialized.discriminant = fd_stake_state_v2_enum_uninitialized;
2289 126 : rc = set_state( ctx, stake_account_index, &uninitialized );
2290 126 : if( FD_UNLIKELY( rc ) ) return rc;
2291 126 : }
2292 :
2293 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L895
2294 237 : rc = fd_account_checked_sub_lamports( ctx, stake_account_index, lamports );
2295 237 : if( FD_UNLIKELY( rc ) ) return rc;
2296 :
2297 576 : } FD_BORROWED_ACCOUNT_DROP( stake_account );
2298 :
2299 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L897
2300 924 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, to_index, to ) {
2301 :
2302 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L899
2303 231 : rc = fd_account_checked_add_lamports( ctx, to_index, lamports );
2304 231 : if( FD_UNLIKELY( rc ) ) return rc;
2305 :
2306 231 : } FD_BORROWED_ACCOUNT_DROP( to );
2307 :
2308 207 : return 0;
2309 231 : }
2310 :
2311 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L903
2312 : static int
2313 : deactivate_delinquent( fd_exec_instr_ctx_t * ctx,
2314 : fd_borrowed_account_t * stake_account,
2315 : ulong stake_acc_index,
2316 : ulong delinquent_vote_account_index,
2317 : ulong reference_vote_account_index,
2318 : ulong current_epoch,
2319 1326 : uint * custom_err ) {
2320 1326 : int rc;
2321 :
2322 1326 : fd_valloc_t scratch_valloc = fd_scratch_virtual();
2323 :
2324 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L911
2325 1326 : fd_pubkey_t const * delinquent_vote_account_pubkey =
2326 1326 : &ctx->instr->acct_pubkeys[delinquent_vote_account_index];
2327 :
2328 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L915
2329 5067 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, delinquent_vote_account_index, delinquent_vote_account ) {
2330 :
2331 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L917
2332 1089 : if( FD_UNLIKELY( memcmp( &delinquent_vote_account->const_meta->info.owner, fd_solana_vote_program_id.key, 32UL ) ) )
2333 48 : return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
2334 :
2335 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L920-L922
2336 1041 : fd_vote_state_versioned_t delinquent_vote_state_versioned = {0};
2337 1041 : rc = fd_vote_get_state( delinquent_vote_account, scratch_valloc, &delinquent_vote_state_versioned );
2338 1041 : if( FD_UNLIKELY( rc ) ) return rc;
2339 696 : fd_vote_convert_to_current( &delinquent_vote_state_versioned, scratch_valloc );
2340 696 : fd_vote_state_t delinquent_vote_state = delinquent_vote_state_versioned.inner.current;
2341 :
2342 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L924
2343 2784 : FD_BORROWED_ACCOUNT_TRY_BORROW_IDX( ctx, reference_vote_account_index, reference_vote_account ) {
2344 :
2345 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L926
2346 696 : if( FD_UNLIKELY( memcmp( &reference_vote_account->const_meta->info.owner, fd_solana_vote_program_id.key, 32UL ) ) )
2347 9 : return FD_EXECUTOR_INSTR_ERR_INCORRECT_PROGRAM_ID;
2348 :
2349 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L929-L932
2350 687 : fd_vote_state_versioned_t reference_vote_state_versioned = {0};
2351 687 : rc = fd_vote_get_state( reference_vote_account, scratch_valloc, &reference_vote_state_versioned );
2352 687 : if( FD_UNLIKELY( rc ) ) return rc;
2353 681 : fd_vote_convert_to_current( &reference_vote_state_versioned, scratch_valloc );
2354 681 : fd_vote_state_t reference_vote_state = reference_vote_state_versioned.inner.current;
2355 :
2356 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L933
2357 681 : if( !acceptable_reference_epoch_credits( reference_vote_state.epoch_credits, current_epoch ) ) {
2358 189 : ctx->txn_ctx->custom_err = FD_STAKE_ERR_INSUFFICIENT_REFERENCE_VOTES;
2359 189 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
2360 189 : }
2361 :
2362 492 : fd_stake_state_v2_t stake_state = {0};
2363 492 : rc = get_state( stake_account, fd_scratch_virtual(), &stake_state );
2364 492 : if( FD_UNLIKELY( rc ) ) return rc;
2365 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L937
2366 492 : if( FD_LIKELY( stake_state.discriminant==fd_stake_state_v2_enum_stake ) ) {
2367 492 : fd_stake_t * stake = &stake_state.inner.stake.stake;
2368 :
2369 492 : if( FD_UNLIKELY( memcmp( &stake->delegation.voter_pubkey, delinquent_vote_account_pubkey, sizeof(fd_pubkey_t) ) ) ) {
2370 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L939
2371 24 : *custom_err = FD_STAKE_ERR_VOTE_ADDRESS_MISMATCH;
2372 24 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
2373 24 : }
2374 :
2375 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L944
2376 468 : if( FD_LIKELY( eligible_for_deactivate_delinquent( delinquent_vote_state.epoch_credits,
2377 468 : current_epoch ) ) ) {
2378 264 : rc = stake_deactivate( stake, current_epoch, custom_err );
2379 264 : if( FD_UNLIKELY( rc ) ) return rc;
2380 72 : rc = set_state( ctx, stake_acc_index, &stake_state );
2381 204 : } else {
2382 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L948
2383 204 : *custom_err = FD_STAKE_ERR_MINIMUM_DELIQUENT_EPOCHS_FOR_DEACTIVATION_NOT_MET;
2384 204 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
2385 204 : }
2386 468 : } else {
2387 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_state.rs#L951
2388 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_DATA;
2389 0 : }
2390 :
2391 696 : } FD_BORROWED_ACCOUNT_DROP( reference_vote_account );
2392 1089 : } FD_BORROWED_ACCOUNT_DROP( delinquent_vote_account );
2393 :
2394 72 : return rc;
2395 1326 : }
2396 :
2397 : /**********************************************************************/
2398 : /* mod stake_instruction */
2399 : /**********************************************************************/
2400 :
2401 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L25
2402 : static int
2403 : get_optional_pubkey( fd_exec_instr_ctx_t * ctx,
2404 : ulong acc_idx,
2405 : int should_be_signer,
2406 1311 : /* out */ fd_pubkey_t const ** pubkey ) {
2407 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L32
2408 1311 : if( FD_LIKELY( acc_idx<ctx->instr->acct_cnt ) ) {
2409 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L33
2410 648 : if( FD_UNLIKELY( should_be_signer && !fd_instr_acc_is_signer_idx( ctx->instr, acc_idx ) ) ) {
2411 63 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2412 63 : }
2413 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L39
2414 585 : *pubkey = &ctx->instr->acct_pubkeys[acc_idx];
2415 663 : } else {
2416 663 : *pubkey = NULL;
2417 663 : }
2418 1248 : return 0;
2419 1311 : }
2420 :
2421 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L60
2422 : static int
2423 : get_stake_account( fd_exec_instr_ctx_t const * ctx,
2424 12882 : fd_borrowed_account_t ** out ) {
2425 :
2426 12882 : if( FD_UNLIKELY( ctx->instr->acct_cnt<1 ) )
2427 96 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2428 :
2429 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L61
2430 12786 : do {
2431 12786 : int err = fd_instr_borrowed_account_view_idx( ctx, 0, out );
2432 12786 : if( FD_UNLIKELY( err ) ) FD_LOG_ERR(( "fd_instr_borrowed_account_view_idx failed (%d-%s)", err, fd_acc_mgr_strerror( err ) ));
2433 12786 : } while(0);
2434 :
2435 12786 : fd_borrowed_account_t * account = *out;
2436 12786 : if( FD_UNLIKELY( !fd_borrowed_account_acquire_write( account ) ) )
2437 0 : return FD_EXECUTOR_INSTR_ERR_ACC_BORROW_FAILED;
2438 :
2439 : // https://github.com/https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L62-L65
2440 12786 : if( FD_UNLIKELY( memcmp( account->const_meta->info.owner, fd_solana_stake_program_id.key, 32UL ) ) )
2441 663 : return FD_EXECUTOR_INSTR_ERR_INVALID_ACC_OWNER;
2442 :
2443 12123 : return FD_EXECUTOR_INSTR_SUCCESS;
2444 12786 : }
2445 :
2446 : /**********************************************************************/
2447 : /* Public API */
2448 : /**********************************************************************/
2449 :
2450 : int
2451 21243 : fd_stake_program_execute( fd_exec_instr_ctx_t * ctx ) {
2452 21243 : FD_EXEC_CU_UPDATE( ctx, DEFAULT_COMPUTE_UNITS );
2453 :
2454 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L77
2455 17373 : fd_pubkey_t const * signers[FD_TXN_SIG_MAX] = {0};
2456 17373 : fd_instr_get_signers( ctx->instr, signers );
2457 :
2458 17373 : if( FD_UNLIKELY( ctx->instr->data==NULL ) ) {
2459 69 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2460 69 : }
2461 :
2462 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L79
2463 17304 : fd_valloc_t valloc = fd_scratch_virtual();
2464 17304 : fd_bincode_decode_ctx_t decode =
2465 17304 : { .valloc = valloc,
2466 17304 : .data = ctx->instr->data,
2467 17304 : .dataend = ctx->instr->data + ctx->instr->data_sz };
2468 :
2469 17304 : fd_stake_instruction_t instruction[1];
2470 17304 : int decode_result = fd_stake_instruction_decode( instruction, &decode );
2471 : /* Fail if the number of bytes consumed by deserialize exceeds 1232
2472 : (hardcoded constant by Agave limited_deserialize) */
2473 17304 : if( decode_result!=FD_BINCODE_SUCCESS ||
2474 17304 : (ulong)ctx->instr->data + 1232UL<(ulong)decode.data )
2475 984 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
2476 :
2477 : /* The EpochRewards sysvar only exists after partitioned epoch rewards is activated.
2478 : If the sysvar exists, check the `active` field */
2479 16320 : fd_sysvar_epoch_rewards_t const * rewards = fd_sysvar_cache_epoch_rewards( ctx->slot_ctx->sysvar_cache );
2480 16320 : int epoch_rewards_active = (NULL != rewards) ? rewards->active : false;
2481 :
2482 16320 : if (epoch_rewards_active && instruction->discriminant!=fd_stake_instruction_enum_get_minimum_delegation) {
2483 234 : ctx->txn_ctx->custom_err = FD_STAKE_ERR_EPOCH_REWARDS_ACTIVE;
2484 234 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
2485 234 : }
2486 :
2487 : /* Replicate stake account changes to bank caches after processing the
2488 : transaction's instructions. */
2489 16086 : ctx->txn_ctx->dirty_stake_acc = 1;
2490 :
2491 16086 : int rc;
2492 : // PLEASE PRESERVE SWITCH-CASE ORDERING TO MIRROR AGAVE IMPL:
2493 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L84
2494 16086 : switch( instruction->discriminant ) {
2495 :
2496 : /* Initialize
2497 : *
2498 : * Instruction:
2499 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L110
2500 : *
2501 : * Processor:
2502 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L85
2503 : */
2504 507 : case fd_stake_instruction_enum_initialize: {
2505 507 : fd_stake_authorized_t const * authorized = &instruction->inner.initialize.authorized;
2506 507 : fd_stake_lockup_t const * lockup = &instruction->inner.initialize.lockup;
2507 :
2508 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L86
2509 507 : fd_borrowed_account_t * me = NULL;
2510 507 : rc = get_stake_account( ctx, &me ); /* acquire_write */
2511 507 : if( FD_UNLIKELY( rc ) ) return rc;
2512 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L87
2513 396 : fd_rent_t const * rent = fd_sysvar_from_instr_acct_rent( ctx, 1, &rc );
2514 396 : if( FD_UNLIKELY( !rent ) ) return rc;
2515 :
2516 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L88
2517 354 : rc = initialize( ctx, me, 0, authorized, lockup, rent );
2518 :
2519 354 : fd_borrowed_account_release_write( me ); /* implicit drop */
2520 354 : break;
2521 396 : }
2522 :
2523 : /* Authorize
2524 : *
2525 : * Instruction:
2526 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L120
2527 : *
2528 : * Processor:
2529 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L90
2530 : */
2531 567 : case fd_stake_instruction_enum_authorize: {
2532 567 : fd_pubkey_t const * authorized_pubkey = &instruction->inner.authorize.pubkey;
2533 567 : fd_stake_authorize_t const * stake_authorize = &instruction->inner.authorize.stake_authorize;
2534 :
2535 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L91
2536 567 : fd_borrowed_account_t * me = NULL;
2537 567 : rc = get_stake_account( ctx, &me );
2538 567 : if( FD_UNLIKELY( rc ) ) return rc;
2539 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L92
2540 516 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 1, &rc );
2541 516 : if( FD_UNLIKELY( !clock ) ) return rc;
2542 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L94
2543 438 : if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) )
2544 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2545 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L95
2546 438 : fd_pubkey_t const * custodian_pubkey = NULL;
2547 438 : rc = get_optional_pubkey( ctx, 3, 0, &custodian_pubkey );
2548 438 : if( FD_UNLIKELY( rc ) ) return rc;
2549 :
2550 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L98
2551 438 : rc = authorize( ctx,
2552 438 : me,
2553 438 : 0,
2554 438 : signers,
2555 438 : authorized_pubkey,
2556 438 : stake_authorize,
2557 438 : clock,
2558 438 : custodian_pubkey,
2559 438 : &ctx->txn_ctx->custom_err );
2560 :
2561 438 : fd_borrowed_account_release_write( me ); /* implicit drop */
2562 438 : break;
2563 438 : }
2564 :
2565 : /* AuthorizeWithSeed
2566 : *
2567 : * Instruction:
2568 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L211
2569 : *
2570 : * Processor:
2571 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L107
2572 : */
2573 378 : case fd_stake_instruction_enum_authorize_with_seed: {
2574 378 : fd_authorize_with_seed_args_t args = instruction->inner.authorize_with_seed;
2575 :
2576 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L108
2577 378 : fd_borrowed_account_t * me = NULL;
2578 378 : rc = get_stake_account( ctx, &me );
2579 378 : if( FD_UNLIKELY( rc ) ) return rc;
2580 :
2581 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L109
2582 363 : if( ctx->instr->acct_cnt<2 )
2583 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2584 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L110
2585 363 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 2, &rc );
2586 363 : if( FD_UNLIKELY( !clock ) ) return rc;
2587 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L112
2588 351 : fd_pubkey_t const * custodian_pubkey = NULL;
2589 351 : rc = get_optional_pubkey( ctx, 3, 0, &custodian_pubkey );
2590 351 : if( FD_UNLIKELY( rc ) ) return rc;
2591 :
2592 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L115
2593 351 : rc = authorize_with_seed( ctx,
2594 351 : me,
2595 351 : 0,
2596 351 : 1,
2597 351 : (char const *)args.authority_seed,
2598 351 : args.authority_seed_len,
2599 351 : &args.authority_owner,
2600 351 : &args.new_authorized_pubkey,
2601 351 : &args.stake_authorize,
2602 351 : clock,
2603 351 : custodian_pubkey );
2604 :
2605 351 : fd_borrowed_account_release_write( me ); /* implicit drop */
2606 351 : break;
2607 351 : }
2608 :
2609 : /* DelegateStake
2610 : *
2611 : * Instruction:
2612 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L135
2613 : *
2614 : * Processor:
2615 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L128
2616 : */
2617 1479 : case fd_stake_instruction_enum_delegate_stake: {
2618 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L129
2619 1479 : fd_borrowed_account_t * me = NULL;
2620 1479 : rc = get_stake_account( ctx, &me );
2621 1479 : if( FD_UNLIKELY( rc ) ) return rc;
2622 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L130
2623 1449 : if( FD_UNLIKELY( ctx->instr->acct_cnt<2 ) )
2624 42 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2625 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L131
2626 1407 : fd_sol_sysvar_clock_t const * clock =
2627 1407 : fd_sysvar_from_instr_acct_clock( ctx, 2, &rc );
2628 1407 : if( FD_UNLIKELY( !clock ) ) return rc;
2629 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L133
2630 1284 : fd_stake_history_t const * stake_history =
2631 1284 : fd_sysvar_from_instr_acct_stake_history( ctx, 3, &rc );
2632 1284 : if( FD_UNLIKELY( !stake_history ) ) return rc;
2633 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L138
2634 1275 : if( FD_UNLIKELY( ctx->instr->acct_cnt<5 ) )
2635 3 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2636 1272 : fd_borrowed_account_release_write( me ); /* implicit drop */
2637 :
2638 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L140
2639 1272 : rc = delegate( ctx,
2640 1272 : 0,
2641 1272 : 1,
2642 1272 : clock,
2643 1272 : stake_history,
2644 1272 : signers );
2645 :
2646 1272 : break;
2647 1275 : }
2648 :
2649 : /* Split
2650 : *
2651 : * Instruction:
2652 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L143
2653 : *
2654 : * Processor:
2655 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L152
2656 : */
2657 2847 : case fd_stake_instruction_enum_split: {
2658 2847 : ulong lamports = instruction->inner.split;
2659 :
2660 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L153
2661 2847 : fd_borrowed_account_t * me = NULL;
2662 2847 : rc = get_stake_account( ctx, &me );
2663 2847 : if( FD_UNLIKELY( rc ) ) return rc;
2664 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L154
2665 2781 : if( FD_UNLIKELY( ctx->instr->acct_cnt<2 ) )
2666 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2667 2781 : fd_borrowed_account_release_write( me ); /* implicit drop */
2668 :
2669 : //https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L156
2670 2781 : rc = split( ctx, 0, lamports, 1, signers );
2671 2781 : break;
2672 2781 : }
2673 :
2674 : /* Merge
2675 : *
2676 : * Instruction:
2677 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L201
2678 : *
2679 : * Processor:
2680 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L166
2681 : */
2682 2004 : case fd_stake_instruction_enum_merge: {
2683 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L167
2684 2004 : fd_borrowed_account_t * me = NULL;
2685 2004 : rc = get_stake_account( ctx, &me );
2686 2004 : if( FD_UNLIKELY( rc ) ) return rc;
2687 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L168
2688 1956 : if( FD_UNLIKELY( ctx->instr->acct_cnt<2 ) )
2689 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2690 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L169
2691 1956 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 2, &rc );
2692 1956 : if( FD_UNLIKELY( rc ) ) return rc;
2693 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L171
2694 1647 : fd_stake_history_t const * stake_history = fd_sysvar_from_instr_acct_stake_history( ctx, 3, &rc );
2695 1647 : if( FD_UNLIKELY( rc ) ) return rc;
2696 :
2697 1635 : fd_borrowed_account_release_write( me ); /* implicit drop */
2698 :
2699 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L177
2700 1635 : rc = merge( ctx, 0, 1, clock, stake_history, signers );
2701 1635 : break;
2702 1647 : }
2703 :
2704 : /* Withdraw
2705 : *
2706 : * Instruction:
2707 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L157
2708 : *
2709 : * Processor:
2710 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L188
2711 : */
2712 894 : case fd_stake_instruction_enum_withdraw: FD_SCRATCH_SCOPE_BEGIN {
2713 894 : ulong lamports = instruction->inner.withdraw;
2714 :
2715 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L189
2716 894 : fd_borrowed_account_t * me = NULL;
2717 894 : rc = get_stake_account( ctx, &me ); /* calls acquire_write */
2718 894 : if( FD_UNLIKELY( rc ) ) return rc;
2719 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L190
2720 861 : if( FD_UNLIKELY( ctx->instr->acct_cnt<2 ) )
2721 24 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2722 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L191
2723 837 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 2, &rc );
2724 837 : if( FD_UNLIKELY( !clock ) ) return rc;
2725 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L193
2726 687 : fd_stake_history_t const * stake_history = fd_sysvar_from_instr_acct_stake_history( ctx, 3, &rc );
2727 687 : if( FD_UNLIKELY( !stake_history ) ) return rc;
2728 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L198
2729 654 : if( FD_UNLIKELY( ctx->instr->acct_cnt<5 ) )
2730 3 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2731 :
2732 651 : fd_borrowed_account_release_write( me ); /* implicit drop */
2733 :
2734 651 : uchar custodian_index = 5;
2735 651 : ulong new_rate_activation_epoch = ULONG_MAX;
2736 651 : int err;
2737 651 : int is_some = new_warmup_cooldown_rate_epoch( ctx, &new_rate_activation_epoch, &err );
2738 651 : if( FD_UNLIKELY( err ) ) return err;
2739 :
2740 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L200
2741 651 : rc = withdraw(
2742 651 : ctx,
2743 651 : 0,
2744 651 : lamports,
2745 651 : 1,
2746 651 : clock,
2747 651 : stake_history,
2748 651 : 4,
2749 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L209-L215
2750 651 : fd_ptr_if( ctx->instr->acct_cnt>=6, &custodian_index, NULL ),
2751 651 : fd_ptr_if( is_some, &new_rate_activation_epoch, NULL ) );
2752 :
2753 894 : } FD_SCRATCH_SCOPE_END;
2754 651 : break;
2755 :
2756 : /* Deactivate
2757 : *
2758 : * Instruction:
2759 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L165
2760 : *
2761 : * Processor:
2762 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L217
2763 : */
2764 651 : case fd_stake_instruction_enum_deactivate: {
2765 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L218
2766 579 : fd_borrowed_account_t * me = NULL;
2767 579 : rc = get_stake_account( ctx, &me );
2768 579 : if( FD_UNLIKELY( rc ) ) return rc;
2769 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L219
2770 462 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 1, &rc );
2771 462 : if( FD_UNLIKELY( !clock ) ) return rc;
2772 :
2773 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L221
2774 366 : rc = deactivate( ctx, me, 0, clock, signers, &ctx->txn_ctx->custom_err );
2775 :
2776 366 : fd_borrowed_account_release_write( me ); /* implicit drop */
2777 366 : break;
2778 462 : }
2779 :
2780 : /* SetLockup
2781 : *
2782 : * Instruction:
2783 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L175
2784 : *
2785 : * Processor:
2786 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L223
2787 : */
2788 606 : case fd_stake_instruction_enum_set_lockup: {
2789 606 : fd_lockup_args_t * lockup = &instruction->inner.set_lockup;
2790 :
2791 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L224
2792 606 : fd_borrowed_account_t * me = NULL;
2793 606 : rc = get_stake_account( ctx, &me );
2794 606 : if( FD_UNLIKELY( rc ) ) return rc;
2795 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L225
2796 543 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
2797 543 : if( FD_UNLIKELY( !clock ) )
2798 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2799 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L226
2800 543 : rc = set_lockup( ctx, me, 0, lockup, signers, clock );
2801 :
2802 543 : fd_borrowed_account_release_write( me ); /* implicit drop */
2803 543 : break;
2804 543 : }
2805 :
2806 : /* InitializeChecked
2807 : *
2808 : * Instruction:
2809 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L224
2810 : *
2811 : * Processor:
2812 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L228
2813 : */
2814 186 : case fd_stake_instruction_enum_initialize_checked: {
2815 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L229
2816 186 : fd_borrowed_account_t * me = NULL;
2817 186 : rc = get_stake_account( ctx, &me );
2818 186 : if( FD_UNLIKELY( rc ) ) return rc;
2819 :
2820 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L230
2821 150 : if( FD_UNLIKELY( ctx->instr->acct_cnt<4 ) )
2822 6 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2823 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L231-L236
2824 144 : fd_pubkey_t const * staker_pubkey = &ctx->instr->acct_pubkeys[2];
2825 144 : fd_pubkey_t const * withdrawer_pubkey = &ctx->instr->acct_pubkeys[3];
2826 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L237
2827 144 : if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, 3 ) ) )
2828 45 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2829 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L241
2830 99 : fd_stake_authorized_t authorized = { .staker = *staker_pubkey,
2831 99 : .withdrawer = *withdrawer_pubkey };
2832 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L246
2833 99 : fd_rent_t const * rent = fd_sysvar_from_instr_acct_rent( ctx, 1, &rc );
2834 99 : if( FD_UNLIKELY( !rent ) ) return rc;
2835 :
2836 96 : fd_stake_lockup_t lockup_default = {0};
2837 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L247
2838 96 : rc = initialize( ctx, me, 0, &authorized, &lockup_default, rent );
2839 :
2840 96 : fd_borrowed_account_release_write( me ); /* implicit drop */
2841 96 : break;
2842 99 : }
2843 :
2844 : /* AuthorizeChecked
2845 : *
2846 : * Instruction:
2847 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L238
2848 : *
2849 : * Processor:
2850 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L249
2851 : */
2852 381 : case fd_stake_instruction_enum_authorize_checked: {
2853 381 : fd_stake_authorize_t const * stake_authorize = &instruction->inner.authorize_checked;
2854 :
2855 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L250
2856 381 : fd_borrowed_account_t * me = NULL;
2857 381 : rc = get_stake_account( ctx, &me );
2858 381 : if( FD_UNLIKELY( rc ) ) return rc;
2859 :
2860 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L251
2861 348 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 1, &rc );
2862 348 : if( FD_UNLIKELY( !clock ) ) return rc;
2863 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L253
2864 330 : if( FD_UNLIKELY( ctx->instr->acct_cnt<4 ) )
2865 6 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2866 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L254
2867 324 : fd_pubkey_t const * authorized_pubkey = &ctx->instr->acct_pubkeys[3];
2868 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L257
2869 324 : int is_signer = fd_instr_acc_is_signer_idx( ctx->instr, 3 );
2870 324 : if( FD_UNLIKELY( !is_signer ) ) return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2871 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L260
2872 201 : fd_pubkey_t const * custodian_pubkey = NULL;
2873 201 : rc = get_optional_pubkey( ctx, 4, 0, &custodian_pubkey );
2874 201 : if( FD_UNLIKELY( rc ) ) return rc;
2875 :
2876 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L263
2877 201 : rc = authorize( ctx,
2878 201 : me,
2879 201 : 0,
2880 201 : signers,
2881 201 : authorized_pubkey,
2882 201 : stake_authorize,
2883 201 : clock,
2884 201 : custodian_pubkey,
2885 201 : &ctx->txn_ctx->custom_err );
2886 :
2887 201 : fd_borrowed_account_release_write( me ); /* implicit drop */
2888 201 : break;
2889 201 : }
2890 :
2891 : /* AuthorizeCheckedWithSeed
2892 : *
2893 : * Instruction:
2894 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L252
2895 : *
2896 : * Processor:
2897 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L272
2898 : */
2899 171 : case fd_stake_instruction_enum_authorize_checked_with_seed: {
2900 171 : fd_authorize_checked_with_seed_args_t const * args =
2901 171 : &instruction->inner.authorize_checked_with_seed;
2902 :
2903 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L273
2904 171 : fd_borrowed_account_t * me = NULL;
2905 171 : rc = get_stake_account( ctx, &me );
2906 171 : if( FD_UNLIKELY( rc ) ) return rc;
2907 :
2908 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L274
2909 153 : if( FD_UNLIKELY( ctx->instr->acct_cnt<2 ) )
2910 0 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2911 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L276
2912 153 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_from_instr_acct_clock( ctx, 2, &rc );
2913 153 : if( FD_UNLIKELY( !clock ) ) return rc;
2914 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L277
2915 141 : if( FD_UNLIKELY( ctx->instr->acct_cnt<4 ) )
2916 3 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
2917 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L278
2918 138 : fd_pubkey_t const * authorized_pubkey = &ctx->instr->acct_pubkeys[3];
2919 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L281
2920 138 : int is_signer = fd_instr_acc_is_signer_idx( ctx->instr, 3 );
2921 138 : if( FD_UNLIKELY( !is_signer ) ) return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
2922 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L284
2923 78 : fd_pubkey_t const * custodian_pubkey = NULL;
2924 78 : rc = get_optional_pubkey( ctx, 4, 0, &custodian_pubkey );
2925 78 : if( FD_UNLIKELY( rc ) ) return rc;
2926 :
2927 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L287
2928 78 : rc = authorize_with_seed( ctx,
2929 78 : me,
2930 78 : 0,
2931 78 : 1,
2932 78 : (char const *)args->authority_seed,
2933 78 : args->authority_seed_len,
2934 78 : &args->authority_owner,
2935 78 : authorized_pubkey,
2936 78 : &args->stake_authorize,
2937 78 : clock,
2938 78 : custodian_pubkey );
2939 :
2940 78 : fd_borrowed_account_release_write( me ); /* implicit drop */
2941 78 : break;
2942 78 : }
2943 :
2944 : /* SetLockupChecked
2945 : *
2946 : * Instruction:
2947 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L266
2948 : *
2949 : * Processor:
2950 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L300
2951 : */
2952 300 : case fd_stake_instruction_enum_set_lockup_checked: {
2953 300 : fd_lockup_checked_args_t * lockup_checked = &instruction->inner.set_lockup_checked;
2954 :
2955 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L301
2956 300 : fd_borrowed_account_t * me = NULL;
2957 300 : rc = get_stake_account( ctx, &me ); /* acquire_write */
2958 300 : if( FD_UNLIKELY( rc ) ) return rc;
2959 :
2960 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L302
2961 243 : fd_pubkey_t const * custodian_pubkey = NULL;
2962 243 : rc = get_optional_pubkey( ctx, 2, 1, &custodian_pubkey );
2963 243 : if( FD_UNLIKELY( rc ) ) return rc;
2964 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L305
2965 180 : fd_lockup_args_t lockup = { .unix_timestamp = lockup_checked->unix_timestamp,
2966 180 : .epoch = lockup_checked->epoch,
2967 180 : .custodian = (fd_pubkey_t *)custodian_pubkey }; // FIXME
2968 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L310
2969 180 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
2970 180 : if( FD_UNLIKELY( !clock ) )
2971 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
2972 :
2973 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L311
2974 180 : rc = set_lockup( ctx, me, 0, &lockup, signers, clock );
2975 :
2976 180 : fd_borrowed_account_release_write( me ); /* implicit drop */
2977 180 : break;
2978 180 : }
2979 :
2980 : /* GetMinimumDelegation
2981 : *
2982 : * Instruction:
2983 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L278
2984 : *
2985 : * Processor:
2986 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L313
2987 : */
2988 2223 : case fd_stake_instruction_enum_get_minimum_delegation: {
2989 2223 : ulong minimum_delegation = get_minimum_delegation( ctx->slot_ctx );
2990 2223 : fd_memcpy( &ctx->txn_ctx->return_data.program_id, fd_solana_stake_program_id.key, sizeof(fd_pubkey_t));
2991 2223 : fd_memcpy(ctx->txn_ctx->return_data.data, (uchar*)(&minimum_delegation), sizeof(ulong));
2992 2223 : ctx->txn_ctx->return_data.len = sizeof(ulong);
2993 2223 : rc = 0;
2994 2223 : goto done;
2995 180 : }
2996 :
2997 : /* DeactivateDelinquent
2998 : *
2999 : * Instruction:
3000 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/instruction.rs#L291
3001 : *
3002 : * Processor:
3003 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L321
3004 : */
3005 1434 : case fd_stake_instruction_enum_deactivate_delinquent: {
3006 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L322
3007 1434 : fd_borrowed_account_t * me = NULL;
3008 1434 : rc = get_stake_account( ctx, &me );
3009 1434 : if( FD_UNLIKELY( rc ) ) return rc;
3010 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L323
3011 1377 : if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) )
3012 51 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
3013 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L325
3014 1326 : fd_sol_sysvar_clock_t const * clock = fd_sysvar_cache_clock( ctx->slot_ctx->sysvar_cache );
3015 1326 : if( FD_UNLIKELY( !clock ) )
3016 0 : return FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_SYSVAR;
3017 :
3018 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L326
3019 1326 : rc = deactivate_delinquent( ctx, me, 0, 1, 2, clock->epoch, &ctx->txn_ctx->custom_err );
3020 :
3021 1326 : fd_borrowed_account_release_write( me ); /* implicit drop */
3022 1326 : break;
3023 1326 : }
3024 :
3025 : /* Redelegate
3026 : *
3027 : * Deprecated:
3028 : * https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/programs/stake/src/stake_instruction.rs#L336
3029 : */
3030 549 : case fd_stake_instruction_enum_redelegate: {
3031 549 : fd_borrowed_account_t * me = NULL;
3032 549 : rc = get_stake_account( ctx, &me );
3033 549 : if( FD_UNLIKELY( rc ) ) return rc;
3034 :
3035 525 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
3036 549 : }
3037 : /* MoveStake
3038 : *
3039 : * Instruction:
3040 : * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/sdk/program/src/stake/instruction.rs#L330
3041 : *
3042 : * Processor:
3043 : * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L356
3044 : */
3045 600 : case fd_stake_instruction_enum_move_stake: {
3046 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L359
3047 600 : if( FD_LIKELY( FD_FEATURE_ACTIVE( ctx->slot_ctx, move_stake_and_move_lamports_ixs ) ) ) {
3048 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L361
3049 480 : if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) )
3050 3 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
3051 :
3052 477 : ulong lamports = instruction->inner.move_stake;
3053 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L362
3054 477 : rc = move_stake( ctx,
3055 477 : 0UL,
3056 477 : lamports,
3057 477 : 1UL,
3058 477 : 2UL,
3059 477 : &ctx->txn_ctx->custom_err );
3060 477 : } else {
3061 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L372
3062 120 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
3063 120 : }
3064 477 : break;
3065 600 : }
3066 : /* MoveLamports
3067 : *
3068 : * Instruction:
3069 : * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/sdk/program/src/stake/instruction.rs#L345
3070 : *
3071 : * Processor:
3072 : * https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L375
3073 : */
3074 477 : case fd_stake_instruction_enum_move_lamports: {
3075 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L378
3076 381 : if( FD_LIKELY( FD_FEATURE_ACTIVE( ctx->slot_ctx, move_stake_and_move_lamports_ixs ) ) ) {
3077 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L380
3078 294 : if( FD_UNLIKELY( ctx->instr->acct_cnt<3 ) )
3079 3 : return FD_EXECUTOR_INSTR_ERR_NOT_ENOUGH_ACC_KEYS;
3080 :
3081 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L381
3082 291 : ulong lamports = instruction->inner.move_lamports;
3083 :
3084 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L381
3085 291 : rc = move_lamports( ctx,
3086 291 : 0UL,
3087 291 : lamports,
3088 291 : 1UL,
3089 291 : 2UL );
3090 291 : } else {
3091 : // https://github.com/anza-xyz/agave/blob/cdff19c7807b006dd63429114fb1d9573bf74172/programs/stake/src/stake_instruction.rs#L391
3092 87 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
3093 87 : }
3094 291 : break;
3095 381 : }
3096 291 : default:
3097 0 : FD_LOG_ERR(( "unsupported stake instruction: %u", instruction->discriminant ));
3098 16086 : }
3099 :
3100 13263 : done:
3101 13263 : return rc;
3102 16086 : }
3103 :
3104 : /* Public API *********************************************************/
3105 :
3106 : static void
3107 0 : write_stake_config( fd_exec_slot_ctx_t * slot_ctx, fd_stake_config_t const * stake_config ) {
3108 0 : ulong data_sz = fd_stake_config_size( stake_config );
3109 0 : fd_pubkey_t const * acc_key = &fd_solana_stake_program_config_id;
3110 0 : fd_account_meta_t * acc_meta = NULL;
3111 0 : uchar * acc_data = NULL;
3112 0 : FD_BORROWED_ACCOUNT_DECL(rec);
3113 0 : int err = fd_acc_mgr_modify( slot_ctx->acc_mgr, slot_ctx->funk_txn, acc_key, 1, data_sz, rec );
3114 0 : FD_TEST( !err );
3115 :
3116 0 : acc_meta = rec->meta;
3117 0 : acc_data = rec->data;
3118 0 : acc_meta->dlen = data_sz;
3119 0 : acc_meta->info.lamports = 960480UL;
3120 0 : acc_meta->info.rent_epoch = 0UL;
3121 0 : acc_meta->info.executable = 0;
3122 :
3123 0 : fd_bincode_encode_ctx_t ctx3;
3124 0 : ctx3.data = acc_data;
3125 0 : ctx3.dataend = acc_data + data_sz;
3126 0 : if( fd_stake_config_encode( stake_config, &ctx3 ) )
3127 0 : FD_LOG_ERR( ( "fd_stake_config_encode failed" ) );
3128 :
3129 0 : fd_memset( acc_data, 0, data_sz );
3130 0 : fd_memcpy( acc_data, stake_config, sizeof( fd_stake_config_t ) );
3131 0 : }
3132 :
3133 : void
3134 0 : fd_stake_program_config_init( fd_exec_slot_ctx_t * slot_ctx ) {
3135 : // https://github.com/anza-xyz/agave/blob/c8685ce0e1bb9b26014f1024de2cd2b8c308cbde/sdk/program/src/stake/config.rs#L26
3136 0 : fd_stake_config_t stake_config = {
3137 0 : .warmup_cooldown_rate = DEFAULT_WARMUP_COOLDOWN_RATE,
3138 0 : .slash_penalty = DEFAULT_SLASH_PENALTY,
3139 0 : };
3140 0 : write_stake_config( slot_ctx, &stake_config );
3141 0 : }
3142 :
3143 : int
3144 : fd_stake_get_state( fd_borrowed_account_t const * self,
3145 : fd_valloc_t const * valloc,
3146 0 : fd_stake_state_v2_t * out ) {
3147 0 : return get_state( self, *valloc, out );
3148 0 : }
3149 :
3150 : fd_stake_history_entry_t
3151 : fd_stake_activating_and_deactivating( fd_delegation_t const * self,
3152 : ulong target_epoch,
3153 : fd_stake_history_t const * stake_history,
3154 0 : ulong * new_rate_activation_epoch ) {
3155 0 : return stake_activating_and_deactivating(
3156 0 : self, target_epoch, stake_history, new_rate_activation_epoch );
3157 0 : }
3158 :
3159 : /* Removes stake delegation from epoch stakes and updates vote account */
3160 : static void
3161 0 : fd_stakes_remove_stake_delegation( fd_exec_slot_ctx_t * slot_ctx, fd_borrowed_account_t * stake_account ) {
3162 0 : fd_stake_accounts_pair_t_mapnode_t key;
3163 0 : fd_memcpy( key.elem.key.uc, stake_account->pubkey->uc, sizeof(fd_pubkey_t) );
3164 0 : if( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool==NULL ) {
3165 0 : FD_LOG_DEBUG(("Stake accounts pool does not exist"));
3166 0 : return;
3167 0 : }
3168 0 : fd_stake_accounts_pair_t_mapnode_t * entry = fd_stake_accounts_pair_t_map_find( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root, &key );
3169 0 : if (FD_UNLIKELY( entry )) {
3170 0 : fd_stake_accounts_pair_t_map_remove( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, &slot_ctx->slot_bank.stake_account_keys.stake_accounts_root, entry);
3171 : // TODO: do we need a release here?
3172 0 : }
3173 0 : }
3174 :
3175 : /* Updates stake delegation in epoch stakes */
3176 : static void
3177 0 : fd_stakes_upsert_stake_delegation( fd_exec_slot_ctx_t * slot_ctx, fd_borrowed_account_t * stake_account ) {
3178 0 : FD_TEST( stake_account->const_meta->info.lamports!=0 );
3179 0 : fd_epoch_bank_t * epoch_bank = fd_exec_epoch_ctx_epoch_bank( slot_ctx->epoch_ctx );
3180 0 : fd_stakes_t * stakes = &epoch_bank->stakes;
3181 :
3182 0 : fd_delegation_pair_t_mapnode_t key;
3183 0 : fd_memcpy(&key.elem.account, stake_account->pubkey->uc, sizeof(fd_pubkey_t));
3184 :
3185 0 : if( stakes->stake_delegations_pool==NULL) {
3186 0 : FD_LOG_DEBUG(("Stake delegations pool does not exist"));
3187 0 : return;
3188 0 : }
3189 :
3190 0 : fd_delegation_pair_t_mapnode_t * entry = fd_delegation_pair_t_map_find( stakes->stake_delegations_pool, stakes->stake_delegations_root, &key);
3191 0 : if( FD_UNLIKELY( !entry ) ) {
3192 0 : fd_stake_accounts_pair_t_mapnode_t key;
3193 0 : fd_memcpy( key.elem.key.uc, stake_account->pubkey->uc, sizeof(fd_pubkey_t) );
3194 0 : if( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool==NULL) {
3195 0 : FD_LOG_DEBUG(("Stake accounts pool does not exist"));
3196 0 : return;
3197 0 : }
3198 0 : fd_stake_accounts_pair_t_mapnode_t * stake_entry = fd_stake_accounts_pair_t_map_find( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root, &key );
3199 0 : if( stake_entry ) {
3200 0 : stake_entry->elem.exists = 1;
3201 0 : } else {
3202 0 : fd_stake_accounts_pair_t_mapnode_t * new_node = fd_stake_accounts_pair_t_map_acquire( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool );
3203 0 : ulong size = fd_stake_accounts_pair_t_map_size( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, slot_ctx->slot_bank.stake_account_keys.stake_accounts_root );
3204 0 : FD_LOG_DEBUG(("Curr stake account size %lu %p", size, (void *)slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool));
3205 0 : if( new_node==NULL ) {
3206 0 : FD_LOG_ERR(("Stake accounts keys map full %lu", size));
3207 0 : }
3208 0 : new_node->elem.exists = 1;
3209 0 : fd_memcpy( new_node->elem.key.uc, stake_account->pubkey->uc, sizeof(fd_pubkey_t) );
3210 0 : fd_stake_accounts_pair_t_map_insert( slot_ctx->slot_bank.stake_account_keys.stake_accounts_pool, &slot_ctx->slot_bank.stake_account_keys.stake_accounts_root, new_node );
3211 0 : }
3212 0 : }
3213 0 : }
3214 :
3215 0 : void fd_store_stake_delegation( fd_exec_slot_ctx_t * slot_ctx, fd_borrowed_account_t * stake_account ) {
3216 0 : fd_pubkey_t const * owner = (fd_pubkey_t const *)stake_account->const_meta->info.owner;
3217 :
3218 0 : if( memcmp( owner->uc, fd_solana_stake_program_id.key, sizeof(fd_pubkey_t) ) ) {
3219 0 : return;
3220 0 : }
3221 :
3222 0 : int is_empty = stake_account->const_meta->info.lamports==0;
3223 0 : int is_uninit = 1;
3224 0 : if( stake_account->const_meta->dlen>=4 ) {
3225 0 : uint prefix = FD_LOAD( uint, stake_account->const_data );
3226 0 : is_uninit = ( prefix==fd_stake_state_v2_enum_uninitialized );
3227 0 : }
3228 :
3229 0 : if( is_empty || is_uninit ) {
3230 0 : fd_stakes_remove_stake_delegation( slot_ctx, stake_account );
3231 0 : } else {
3232 0 : fd_stakes_upsert_stake_delegation( slot_ctx, stake_account );
3233 0 : }
3234 0 : }
|