Line data Source code
1 : #include "fd_system_program.h"
2 : #include "../fd_executor.h"
3 : #include "../fd_borrowed_account.h"
4 : #include "../fd_system_ids.h"
5 : #include "../fd_pubkey_utils.h"
6 : #include "../../log_collector/fd_log_collector.h"
7 :
8 : /* The dynamically sized portion of the system program instruction only
9 : comes from the seed. This means in the worst case assuming that the
10 : seed takes up the entire transaction MTU, the worst case footprint
11 : is the sum of the size of the instruction and the transaction MTU.
12 : This is not the tightest bound, but it's a reasonable bound. */
13 :
14 : #define FD_SYSTEM_PROGRAM_INSTR_FOOTPRINT (FD_TXN_MTU + sizeof(fd_system_program_instruction_t))
15 :
16 : #define FD_FMT_ADDRESS(account_b58, base, out_fmt) \
17 434 : char out_fmt[ 128UL ]; \
18 434 : if( base ) { \
19 110 : FD_BASE58_ENCODE_32_BYTES( base->key, base_b58 ); \
20 110 : snprintf( out_fmt, 128UL, "Address { address: %s, base: Some(%s) }", account_b58, base_b58 ); \
21 324 : } else { \
22 324 : snprintf( out_fmt, 128UL, "Address { address: %s, base: None }", account_b58 ); \
23 324 : }
24 :
25 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L42-L68
26 :
27 : Partial port of system_processor::Address::create, only covering the
28 : case of the "seed" input actually existing. Note that this doesn't
29 : "create" an address, but rather re-derives from PDA inputs and checks
30 : that the result matches some expected value. */
31 :
32 : static int
33 : verify_seed_address( fd_exec_instr_ctx_t * ctx,
34 : fd_pubkey_t const * expected,
35 : fd_pubkey_t const * base,
36 : char const * seed,
37 : ulong seed_sz,
38 902 : fd_pubkey_t const * owner ) {
39 :
40 902 : fd_pubkey_t actual[1];
41 902 : do {
42 902 : int err = fd_pubkey_create_with_seed(
43 902 : ctx,
44 902 : base->uc,
45 902 : seed,
46 902 : seed_sz,
47 902 : owner->uc,
48 902 : actual->uc );
49 902 : if( FD_UNLIKELY( err ) ) return err;
50 902 : } while(0);
51 :
52 892 : if( FD_UNLIKELY( 0!=memcmp( actual->uc, expected->uc, sizeof(fd_pubkey_t) ) ) ) {
53 : /* Log msg_sz can be more or less than 127 bytes */
54 384 : FD_BASE58_ENCODE_32_BYTES( expected->key, expected_b58 );
55 384 : FD_BASE58_ENCODE_32_BYTES( actual->key, actual_b58 );
56 384 : fd_log_collector_printf_inefficient_max_512( ctx,
57 384 : "Create: address %s does not match derived address %s",
58 384 : expected_b58, actual_b58 );
59 384 : ctx->txn_out->err.custom_err = FD_SYSTEM_PROGRAM_ERR_ADDR_WITH_SEED_MISMATCH;
60 384 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
61 384 : }
62 :
63 508 : return 0;
64 892 : }
65 :
66 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L183
67 : https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L182
68 :
69 : Matches Solana Labs system_processor::transfer_verified */
70 :
71 : static int
72 : fd_system_program_transfer_verified( fd_exec_instr_ctx_t * ctx,
73 : ulong transfer_amount,
74 : ushort from_acct_idx,
75 642 : ushort to_acct_idx ) {
76 642 : int err;
77 :
78 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L191-L192 */
79 :
80 642 : fd_guarded_borrowed_account_t from = {0};
81 642 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, from_acct_idx, &from );
82 :
83 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L193-L196 */
84 :
85 642 : if( fd_borrowed_account_get_data_len( &from ) != 0UL ) {
86 76 : fd_log_collector_msg_literal( ctx, "Transfer: `from` must not carry data" );
87 76 : return FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
88 76 : }
89 :
90 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L197-L205 */
91 :
92 566 : if( transfer_amount > fd_borrowed_account_get_lamports( &from ) ) {
93 : /* Max msg_sz: 45 - 6 + 20 + 20 = 79 < 127 => we can use printf */
94 24 : fd_log_collector_printf_dangerous_max_127( ctx, "Transfer: insufficient lamports %lu, need %lu", fd_borrowed_account_get_lamports( &from ), transfer_amount );
95 24 : ctx->txn_out->err.custom_err = FD_SYSTEM_PROGRAM_ERR_RESULT_WITH_NEGATIVE_LAMPORTS;
96 24 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
97 24 : }
98 :
99 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L207 */
100 :
101 542 : err = fd_borrowed_account_checked_sub_lamports( &from, transfer_amount );
102 : /* Note: this err can never happen because of the check above */
103 542 : if( FD_UNLIKELY( err ) ) return err;
104 :
105 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L208 */
106 :
107 508 : fd_borrowed_account_drop( &from );
108 :
109 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L209-L210 */
110 :
111 508 : fd_guarded_borrowed_account_t to = {0};
112 508 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, to_acct_idx, &to );
113 :
114 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L211 */
115 :
116 508 : err = fd_borrowed_account_checked_add_lamports( &to, transfer_amount );
117 508 : if( FD_UNLIKELY( err ) ) return err;
118 :
119 484 : return 0;
120 508 : }
121 :
122 : /* https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L214
123 :
124 : Matches system_processor::transfer */
125 :
126 : static int
127 : fd_system_program_transfer( fd_exec_instr_ctx_t * ctx,
128 : ulong transfer_amount,
129 : ushort from_acct_idx,
130 506 : ushort to_acct_idx ) {
131 :
132 : /* https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L222-L232 */
133 :
134 506 : int instr_err_code = 0;
135 506 : if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, from_acct_idx, &instr_err_code ) ) ) {
136 : /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
137 28 : if( FD_UNLIKELY( !!instr_err_code ) ) return instr_err_code;
138 : /* Max msg_sz: 37 - 2 + 45 = 80 < 127 => we can use printf */
139 28 : ushort idx_in_txn = ctx->instr->accounts[ from_acct_idx ].index_in_transaction;
140 28 : FD_BASE58_ENCODE_32_BYTES( ctx->txn_out->accounts.keys[ idx_in_txn ].key, key_b58 );
141 28 : fd_log_collector_printf_dangerous_max_127( ctx,
142 28 : "Transfer: `from` account %s must sign", key_b58 );
143 28 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
144 28 : }
145 :
146 : /* https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L234-L241 */
147 :
148 478 : return fd_system_program_transfer_verified( ctx, transfer_amount, from_acct_idx, to_acct_idx );
149 506 : }
150 :
151 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L71-L111
152 : https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L70
153 :
154 : Based on Solana Labs system_processor::allocate() */
155 :
156 : static int
157 : fd_system_program_allocate( fd_exec_instr_ctx_t * ctx,
158 : fd_borrowed_account_t * account,
159 : ulong space,
160 : fd_pubkey_t const * authority,
161 857 : fd_pubkey_t const * base ) {
162 857 : int err;
163 :
164 : /* Assumes that acct_idx was bounds checked */
165 :
166 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L78-L85 */
167 :
168 857 : if( FD_UNLIKELY( !fd_exec_instr_ctx_any_signed( ctx, authority ) ) ) {
169 : /* Max msg_sz: 35 - 2 + 125 = 158 */
170 109 : FD_BASE58_ENCODE_32_BYTES( account->pubkey->key, account_b58 );
171 109 : FD_FMT_ADDRESS( account_b58, base, address_fmt );
172 109 : fd_log_collector_printf_inefficient_max_512( ctx,
173 109 : "Allocate: 'to' account %s must sign",
174 109 : address_fmt );
175 109 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
176 109 : }
177 :
178 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L87-L96 */
179 :
180 748 : if( FD_UNLIKELY( ( fd_borrowed_account_get_data_len( account ) != 0UL ) ||
181 748 : ( 0!=memcmp( fd_borrowed_account_get_owner( account ), fd_solana_system_program_id.uc, 32UL ) ) ) ) {
182 : /* Max msg_sz: 35 - 2 + 125 = 158 */
183 191 : FD_BASE58_ENCODE_32_BYTES( account->pubkey->key, account_b58 );
184 191 : FD_FMT_ADDRESS( account_b58, base, address_fmt );
185 191 : fd_log_collector_printf_inefficient_max_512( ctx,
186 191 : "Allocate: account %s already in use",
187 191 : address_fmt );
188 191 : ctx->txn_out->err.custom_err = FD_SYSTEM_PROGRAM_ERR_ACCT_ALREADY_IN_USE;
189 191 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
190 191 : }
191 :
192 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L98-L106 */
193 :
194 557 : if( FD_UNLIKELY( space > FD_RUNTIME_ACC_SZ_MAX ) ) {
195 : /* Max msg_sz: 48 - 6 + 2*20 = 82 < 127 => we can use printf */
196 15 : fd_log_collector_printf_dangerous_max_127( ctx,
197 15 : "Allocate: requested %lu, max allowed %lu", space, FD_RUNTIME_ACC_SZ_MAX );
198 15 : ctx->txn_out->err.custom_err = FD_SYSTEM_PROGRAM_ERR_INVALID_ACCT_DATA_LEN;
199 15 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
200 15 : }
201 :
202 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L108 */
203 :
204 542 : err = fd_borrowed_account_set_data_length( account, space );
205 542 : if( FD_UNLIKELY( err ) ) {
206 21 : return err;
207 21 : }
208 :
209 521 : return FD_EXECUTOR_INSTR_SUCCESS;
210 542 : }
211 :
212 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L113-L131
213 : https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L112
214 :
215 : Based on Solana Labs system_processor::assign() */
216 :
217 : static int
218 : fd_system_program_assign( fd_exec_instr_ctx_t * ctx,
219 : fd_borrowed_account_t * account,
220 : fd_pubkey_t const * owner,
221 : fd_pubkey_t const * authority,
222 761 : fd_pubkey_t const * base ) {
223 : /* Assumes addr_idx was bounds checked */
224 :
225 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L121-L123 */
226 :
227 761 : if( 0==memcmp( fd_borrowed_account_get_owner( account ), owner->uc, sizeof(fd_pubkey_t) ) )
228 21 : return 0;
229 :
230 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L125-L128 */
231 :
232 740 : if( FD_UNLIKELY( !fd_exec_instr_ctx_any_signed( ctx, authority ) ) ) {
233 : /* Max msg_sz: 28 - 2 + 125 = 151 */
234 53 : FD_BASE58_ENCODE_32_BYTES( account->pubkey->key, account_b58 );
235 53 : FD_FMT_ADDRESS( account_b58, base, address_fmt );
236 53 : fd_log_collector_printf_inefficient_max_512( ctx,
237 53 : "Assign: account %s must sign",
238 53 : address_fmt );
239 53 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
240 53 : }
241 :
242 687 : return fd_borrowed_account_set_owner( account, owner );
243 740 : }
244 :
245 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L133-L143
246 :
247 : Based on Solana Labs system_processor::allocate_and_assign() */
248 :
249 : static int
250 : fd_system_program_allocate_and_assign( fd_exec_instr_ctx_t * ctx,
251 : fd_borrowed_account_t * account,
252 : ulong space,
253 : fd_pubkey_t const * owner,
254 : fd_pubkey_t const * authority,
255 518 : fd_pubkey_t const * base ) {
256 :
257 518 : do {
258 518 : int err = fd_system_program_allocate( ctx, account, space, authority, base );
259 518 : if( FD_UNLIKELY( err ) ) return err;
260 518 : } while(0);
261 399 : return fd_system_program_assign( ctx, account, owner, authority, base );
262 :
263 518 : }
264 :
265 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L146-L181
266 : https://github.com/anza-xyz/agave/blob/v2.0.9/programs/system/src/system_processor.rs#L145
267 :
268 : Matches Solana Labs system_processor::create_account() */
269 :
270 : static int
271 : fd_system_program_create_account( fd_exec_instr_ctx_t * ctx,
272 : ushort from_acct_idx,
273 : ushort to_acct_idx,
274 : ulong lamports,
275 : ulong space,
276 : fd_pubkey_t const * owner,
277 : fd_pubkey_t const * authority,
278 453 : fd_pubkey_t const * base ) {
279 453 : int err;
280 :
281 : /* if it looks like the to account is already in use, bail
282 : https://github.com/anza-xyz/agave/blob/v2.1.14/programs/system/src/system_processor.rs#L159-L172 */
283 :
284 453 : do {
285 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L160-L161 */
286 :
287 453 : fd_guarded_borrowed_account_t to = {0};
288 453 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, to_acct_idx, &to );
289 :
290 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L162-L169 */
291 :
292 453 : if( FD_UNLIKELY( fd_borrowed_account_get_lamports( &to ) ) ) {
293 : /* Max msg_sz: 41 - 2 + 125 = 164 */
294 81 : FD_BASE58_ENCODE_32_BYTES( to.pubkey->key, to_b58 );
295 81 : FD_FMT_ADDRESS( to_b58, base, address_fmt );
296 81 : fd_log_collector_printf_inefficient_max_512( ctx,
297 81 : "Create Account: account %s already in use",
298 81 : address_fmt );
299 81 : ctx->txn_out->err.custom_err = FD_SYSTEM_PROGRAM_ERR_ACCT_ALREADY_IN_USE;
300 81 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
301 81 : }
302 :
303 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L171 */
304 :
305 372 : err = fd_system_program_allocate_and_assign( ctx, &to, space, owner, authority, base );
306 372 : if( FD_UNLIKELY( err ) ) return err;
307 :
308 : /* Implicit drop
309 : https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L172 */
310 372 : } while (0);
311 :
312 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L173-L180 */
313 :
314 283 : return fd_system_program_transfer( ctx, lamports, from_acct_idx, to_acct_idx );
315 453 : }
316 :
317 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L184-L214 */
318 :
319 : static int
320 : fd_system_program_create_account_allow_prefund( fd_exec_instr_ctx_t * ctx,
321 : ushort to_acct_idx,
322 : ulong lamports,
323 : ulong space,
324 : fd_pubkey_t const * owner,
325 : fd_pubkey_t const * to_address,
326 0 : ushort from_acct_idx ) {
327 0 : int err;
328 :
329 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L198-L201 */
330 0 : do {
331 0 : fd_guarded_borrowed_account_t to = {0};
332 0 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, to_acct_idx, &to );
333 0 : err = fd_system_program_allocate_and_assign( ctx, &to, space, owner, to_address, NULL );
334 0 : if( FD_UNLIKELY( err ) ) return err;
335 0 : } while(0);
336 :
337 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L202-L212 */
338 0 : if( FD_LIKELY( lamports > 0 ) ) {
339 0 : return fd_system_program_transfer( ctx, lamports, from_acct_idx, to_acct_idx );
340 0 : }
341 :
342 0 : return FD_EXECUTOR_INSTR_SUCCESS;
343 0 : }
344 :
345 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L327-L352
346 :
347 : Matches Solana Labs system_processor SystemInstruction::CreateAccount { ... } => { ... } */
348 :
349 : int
350 : fd_system_program_exec_create_account( fd_exec_instr_ctx_t * ctx,
351 212 : fd_system_program_instruction_create_account_t const * create_acc ) {
352 :
353 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L332 */
354 :
355 212 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) )
356 4 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
357 :
358 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L333-L339
359 : Authorization check is lifted out from 'allocate' to here. */
360 :
361 208 : ushort const from_acct_idx = 0UL;
362 208 : ushort const to_acct_idx = 1UL;
363 :
364 : /* https://github.com/anza-xyz/agave/blob/v2.1.14/programs/system/src/system_processor.rs#L317-L320 */
365 208 : fd_pubkey_t const * authority = NULL;
366 208 : int err = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, to_acct_idx, &authority );
367 208 : if( FD_UNLIKELY( err ) ) return err;
368 :
369 208 : return fd_system_program_create_account(
370 208 : ctx,
371 208 : from_acct_idx,
372 208 : to_acct_idx,
373 208 : create_acc->lamports,
374 208 : create_acc->space,
375 208 : &create_acc->owner,
376 208 : authority,
377 208 : NULL );
378 208 : }
379 :
380 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L530-L563 */
381 :
382 : int
383 : fd_system_program_exec_create_account_allow_prefund( fd_exec_instr_ctx_t * ctx,
384 0 : fd_system_program_instruction_create_account_t const * args ) {
385 :
386 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L535-L540 */
387 0 : if( FD_UNLIKELY( !FD_FEATURE_ACTIVE_BANK( ctx->bank, create_account_allow_prefund ) ) ) {
388 0 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
389 0 : }
390 :
391 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L541-L547 */
392 0 : ushort from_acct_idx = 0;
393 0 : if( args->lamports > 0 ) {
394 0 : if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( ctx, 2U ) ) ) {
395 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
396 0 : }
397 0 : from_acct_idx = 1;
398 0 : } else {
399 0 : if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( ctx, 1U ) ) ) {
400 0 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
401 0 : }
402 0 : }
403 :
404 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L548-L552 */
405 0 : ushort const to_acct_idx = 0;
406 0 : fd_pubkey_t const * to_address = NULL;
407 0 : int err = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, to_acct_idx, &to_address );
408 0 : if( FD_UNLIKELY( err ) ) return err;
409 :
410 : /* https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L553-L562 */
411 0 : return fd_system_program_create_account_allow_prefund(
412 0 : ctx, to_acct_idx, args->lamports, args->space, &args->owner, to_address, from_acct_idx );
413 0 : }
414 :
415 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L381-L393
416 :
417 : Matches Solana Labs system_processor SystemInstruction::Assign { ... } => { ... } */
418 :
419 : int
420 : fd_system_program_exec_assign( fd_exec_instr_ctx_t * ctx,
421 251 : fd_pubkey_t const * owner ) {
422 251 : int err;
423 :
424 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L382 */
425 :
426 251 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
427 6 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
428 :
429 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L383-L384 */
430 :
431 245 : fd_guarded_borrowed_account_t account = {0};
432 245 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0, &account );
433 :
434 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L385-L391
435 : system_processor::Address::create eliminated (dead code) */
436 :
437 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L392 */
438 :
439 245 : err = fd_system_program_assign( ctx, &account, owner, account.pubkey, NULL );
440 245 : if( FD_UNLIKELY( err ) ) return err;
441 :
442 : /* Implicit drop */
443 :
444 108 : return 0;
445 245 : }
446 :
447 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L394-L404
448 :
449 : Matches Solana Labs system_processor SystemInstruction::Transfer { ... } => { ... } */
450 :
451 : int
452 : fd_system_program_exec_transfer( fd_exec_instr_ctx_t * ctx,
453 233 : ulong transfer_amount ) {
454 :
455 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L395 */
456 :
457 233 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 2 ) )
458 10 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
459 :
460 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L396-L402 */
461 :
462 223 : return fd_system_program_transfer( ctx, transfer_amount, 0UL, 1UL );
463 233 : }
464 :
465 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L353
466 :
467 : Matches Solana Labs system_processor SystemInstruction::CreateAccountWithSeed { ... } => { ... } */
468 :
469 : int
470 : fd_system_program_exec_create_account_with_seed( fd_exec_instr_ctx_t * ctx,
471 504 : fd_system_program_instruction_create_account_with_seed_t const * args ) {
472 :
473 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L360 */
474 :
475 504 : if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( ctx, 2UL) ) )
476 4 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
477 :
478 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L361-L367 */
479 :
480 500 : fd_pubkey_t const * to_address = NULL;
481 500 : int err = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, 1UL, &to_address );
482 500 : if( FD_UNLIKELY( err ) ) return err;
483 :
484 500 : do {
485 500 : int err = verify_seed_address(
486 500 : ctx,
487 500 : to_address,
488 500 : &args->base,
489 500 : (char const *)args->seed,
490 500 : args->seed_len,
491 500 : &args->owner );
492 500 : if( FD_UNLIKELY( err ) ) return err;
493 500 : } while(0);
494 :
495 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L368-L379 */
496 :
497 245 : ushort const from_acct_idx = 0UL;
498 245 : ushort const to_acct_idx = 1UL;
499 245 : return fd_system_program_create_account(
500 245 : ctx,
501 245 : from_acct_idx,
502 245 : to_acct_idx,
503 245 : args->lamports,
504 245 : args->space,
505 245 : &args->owner,
506 245 : &args->base,
507 245 : &args->base );
508 500 : }
509 :
510 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L504-L516
511 :
512 : Matches Solana Labs system_processor SystemInstruction::Allocate { ... } => { ... } */
513 :
514 : int
515 : fd_system_program_exec_allocate( fd_exec_instr_ctx_t * ctx,
516 355 : ulong space ) {
517 355 : int err;
518 :
519 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L505 */
520 :
521 355 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
522 16 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
523 :
524 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L506-L507 */
525 339 : fd_guarded_borrowed_account_t account = {0};
526 339 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0, &account );
527 :
528 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L508-L514
529 : system_processor::Address::create eliminated (dead code) */
530 :
531 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L515
532 : Authorization check is lifted out from 'allocate' to here. */
533 :
534 339 : err = fd_system_program_allocate( ctx, &account, space, account.pubkey, NULL );
535 339 : if( FD_UNLIKELY( err ) ) return err;
536 :
537 : /* Implicit drop */
538 :
539 122 : return 0;
540 339 : }
541 :
542 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L517-L541
543 :
544 : Matches Solana Labs system_processor SystemInstruction::AllocateWithSeed { ... } => { ... } */
545 :
546 : int
547 : fd_system_program_exec_allocate_with_seed( fd_exec_instr_ctx_t * ctx,
548 206 : fd_system_program_instruction_allocate_with_seed_t const * args ) {
549 206 : int err;
550 :
551 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L523 */
552 :
553 206 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
554 2 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
555 :
556 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#524-525 */
557 :
558 204 : fd_guarded_borrowed_account_t account = {0};
559 204 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0, &account );
560 :
561 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L526-L532 */
562 :
563 204 : err = verify_seed_address(
564 204 : ctx,
565 204 : account.pubkey,
566 204 : &args->base,
567 204 : (char const *)args->seed,
568 204 : args->seed_len,
569 204 : &args->owner );
570 204 : if( FD_UNLIKELY( err ) ) return err;
571 :
572 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L533-L540
573 : Authorization check is lifted out from 'allocate' to here. */
574 :
575 146 : err = fd_system_program_allocate_and_assign(
576 146 : ctx,
577 146 : &account,
578 146 : args->space,
579 146 : &args->owner,
580 146 : &args->base,
581 146 : &args->base );
582 146 : if( FD_UNLIKELY( err ) ) return err;
583 :
584 : /* Implicit drop */
585 :
586 116 : return 0;
587 146 : }
588 :
589 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L542-L554
590 :
591 : Matches Solana Labs system_processor SystemInstruction::AssignWithSeed { ... } => { ... } */
592 :
593 : int
594 : fd_system_program_exec_assign_with_seed( fd_exec_instr_ctx_t * ctx,
595 200 : fd_system_program_instruction_assign_with_seed_t const * args ) {
596 200 : int err;
597 :
598 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#543 */
599 :
600 200 : if( FD_UNLIKELY( ctx->instr->acct_cnt < 1 ) )
601 2 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
602 :
603 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L544-L545 */
604 :
605 198 : fd_guarded_borrowed_account_t account = {0};
606 198 : FD_TRY_BORROW_INSTR_ACCOUNT_DEFAULT_ERR_CHECK( ctx, 0, &account );
607 :
608 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L546-L552 */
609 :
610 198 : err = verify_seed_address(
611 198 : ctx,
612 198 : account.pubkey,
613 198 : &args->base,
614 198 : (char const *)args->seed,
615 198 : args->seed_len,
616 198 : &args->owner );
617 198 : if( FD_UNLIKELY( err ) ) return err;
618 :
619 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L553
620 : Authorization check is lifted out from 'assign' to here. */
621 :
622 117 : err = fd_system_program_assign( ctx, &account, &args->owner, &args->base, &args->base );
623 117 : if( FD_UNLIKELY( err ) ) return err;
624 :
625 : /* Implicit drop */
626 :
627 96 : return 0;
628 117 : }
629 :
630 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L405-L422
631 :
632 : Matches Solana Labs system_processor SystemInstruction::TransferWithSeed { ... } => { ... } */
633 :
634 : int
635 : fd_system_program_exec_transfer_with_seed( fd_exec_instr_ctx_t * ctx,
636 404 : fd_system_program_instruction_transfer_with_seed_t const * args ) {
637 :
638 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L410 */
639 :
640 404 : if( FD_UNLIKELY( fd_exec_instr_ctx_check_num_insn_accounts( ctx, 3UL ) ) )
641 3 : return FD_EXECUTOR_INSTR_ERR_MISSING_ACC;
642 :
643 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L411-L421
644 : Inlined call to system_processor::transfer_with_seed */
645 :
646 401 : ushort const from_idx = 0UL;
647 401 : ushort const from_base_idx = 1UL;
648 401 : ushort const to_idx = 2UL;
649 :
650 401 : int instr_err_code = 0;
651 401 : if( FD_UNLIKELY( !fd_instr_acc_is_signer_idx( ctx->instr, from_base_idx, &instr_err_code ) ) ) {
652 : /* https://github.com/anza-xyz/agave/blob/v3.0.3/transaction-context/src/lib.rs#L789 */
653 113 : if( FD_UNLIKELY( !!instr_err_code ) ) return instr_err_code;
654 : /* Max msg_sz: 37 - 2 + 45 = 80 < 127 => we can use printf */
655 113 : ushort idx_in_txn = ctx->instr->accounts[ from_base_idx ].index_in_transaction;
656 113 : FD_BASE58_ENCODE_32_BYTES( ctx->txn_out->accounts.keys[ idx_in_txn ].key, key_b58 );
657 113 : fd_log_collector_printf_dangerous_max_127( ctx,
658 113 : "Transfer: 'from' account %s must sign", key_b58 );
659 113 : return FD_EXECUTOR_INSTR_ERR_MISSING_REQUIRED_SIGNATURE;
660 113 : }
661 :
662 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/system/src/system_processor.rs#L267-L274 */
663 :
664 288 : fd_pubkey_t const * base = NULL;
665 288 : int err = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, from_base_idx, &base );
666 288 : if( FD_UNLIKELY( err ) ) return err;
667 :
668 288 : fd_pubkey_t address_from_seed[1];
669 288 : do {
670 288 : int err = fd_pubkey_create_with_seed(
671 288 : ctx,
672 288 : base->uc,
673 288 : (char const *)args->from_seed,
674 288 : args->from_seed_len,
675 288 : args->from_owner.uc,
676 288 : address_from_seed->uc );
677 288 : if( FD_UNLIKELY( err ) ) return err;
678 288 : } while(0);
679 :
680 : /* https://github.com/anza-xyz/agave/blob/v2.2.0/programs/system/src/system_processor.rs#L276-L287 */
681 285 : fd_pubkey_t const * from_key = NULL;
682 285 : err = fd_exec_instr_ctx_get_key_of_account_at_index( ctx, from_idx, &from_key );
683 285 : if( FD_UNLIKELY( err ) ) return err;
684 :
685 285 : if( FD_UNLIKELY( 0!=memcmp( address_from_seed->uc,
686 285 : from_key->uc,
687 285 : sizeof(fd_pubkey_t) ) ) ) {
688 : /* Log msg_sz can be more or less than 127 bytes */
689 121 : FD_BASE58_ENCODE_32_BYTES( from_key->key, from_key_b58 );
690 121 : FD_BASE58_ENCODE_32_BYTES( address_from_seed->key, address_from_seed_b58 );
691 121 : fd_log_collector_printf_inefficient_max_512( ctx,
692 121 : "Transfer: 'from' address %s does not match derived address %s",
693 121 : from_key_b58,
694 121 : address_from_seed_b58 );
695 121 : ctx->txn_out->err.custom_err = FD_SYSTEM_PROGRAM_ERR_ADDR_WITH_SEED_MISMATCH;
696 121 : return FD_EXECUTOR_INSTR_ERR_CUSTOM_ERR;
697 121 : }
698 :
699 : /* https://github.com/solana-labs/solana/blob/v1.17.22/programs/system/src/system_processor.rs#L305-L312 */
700 164 : return fd_system_program_transfer_verified( ctx, args->lamports, from_idx, to_idx );
701 285 : }
702 :
703 : int
704 5647 : fd_system_program_execute( fd_exec_instr_ctx_t * ctx ) {
705 5647 : FD_EXEC_CU_UPDATE( ctx, 150UL );
706 5194 : uchar instr_mem[ FD_SYSTEM_PROGRAM_INSTR_FOOTPRINT ] __attribute__((aligned(alignof(fd_system_program_instruction_t))));
707 :
708 5194 : fd_system_program_instruction_t * instruction = fd_bincode_decode_static_limited_deserialize(
709 5194 : system_program_instruction,
710 5194 : instr_mem,
711 5194 : ctx->instr->data,
712 5194 : ctx->instr->data_sz,
713 5194 : FD_TXN_MTU
714 5194 : );
715 5194 : if( FD_UNLIKELY( !instruction ) ) {
716 1226 : return FD_EXECUTOR_INSTR_ERR_INVALID_INSTR_DATA;
717 1226 : }
718 :
719 3968 : int result = FD_EXECUTOR_INSTR_ERR_INVALID_ARG;
720 :
721 3968 : switch( instruction->discriminant ) {
722 212 : case fd_system_program_instruction_enum_create_account: {
723 212 : result = fd_system_program_exec_create_account(
724 212 : ctx, &instruction->inner.create_account );
725 212 : break;
726 0 : }
727 251 : case fd_system_program_instruction_enum_assign: {
728 251 : result = fd_system_program_exec_assign(
729 251 : ctx, &instruction->inner.assign );
730 251 : break;
731 0 : }
732 233 : case fd_system_program_instruction_enum_transfer: {
733 233 : result = fd_system_program_exec_transfer(
734 233 : ctx, instruction->inner.transfer );
735 233 : break;
736 0 : }
737 504 : case fd_system_program_instruction_enum_create_account_with_seed: {
738 504 : result = fd_system_program_exec_create_account_with_seed(
739 504 : ctx, &instruction->inner.create_account_with_seed );
740 504 : break;
741 0 : }
742 354 : case fd_system_program_instruction_enum_advance_nonce_account: {
743 354 : result = fd_system_program_exec_advance_nonce_account( ctx );
744 354 : break;
745 0 : }
746 448 : case fd_system_program_instruction_enum_withdraw_nonce_account: {
747 448 : result = fd_system_program_exec_withdraw_nonce_account(
748 448 : ctx, instruction->inner.withdraw_nonce_account );
749 448 : break;
750 0 : }
751 187 : case fd_system_program_instruction_enum_initialize_nonce_account: {
752 187 : result = fd_system_program_exec_initialize_nonce_account(
753 187 : ctx, &instruction->inner.initialize_nonce_account );
754 187 : break;
755 0 : }
756 419 : case fd_system_program_instruction_enum_authorize_nonce_account: {
757 419 : result = fd_system_program_exec_authorize_nonce_account(
758 419 : ctx, &instruction->inner.authorize_nonce_account );
759 419 : break;
760 0 : }
761 355 : case fd_system_program_instruction_enum_allocate: {
762 355 : result = fd_system_program_exec_allocate( ctx, instruction->inner.allocate );
763 355 : break;
764 0 : }
765 206 : case fd_system_program_instruction_enum_allocate_with_seed: {
766 : // https://github.com/solana-labs/solana/blob/b00d18cec4011bb452e3fe87a3412a3f0146942e/runtime/src/system_instruction_processor.rs#L525
767 206 : result = fd_system_program_exec_allocate_with_seed(
768 206 : ctx, &instruction->inner.allocate_with_seed );
769 206 : break;
770 0 : }
771 200 : case fd_system_program_instruction_enum_assign_with_seed: {
772 : // https://github.com/solana-labs/solana/blob/b00d18cec4011bb452e3fe87a3412a3f0146942e/runtime/src/system_instruction_processor.rs#L545
773 200 : result = fd_system_program_exec_assign_with_seed(
774 200 : ctx, &instruction->inner.assign_with_seed );
775 200 : break;
776 0 : }
777 404 : case fd_system_program_instruction_enum_transfer_with_seed: {
778 : // https://github.com/solana-labs/solana/blob/b00d18cec4011bb452e3fe87a3412a3f0146942e/runtime/src/system_instruction_processor.rs#L412
779 404 : result = fd_system_program_exec_transfer_with_seed(
780 404 : ctx, &instruction->inner.transfer_with_seed );
781 404 : break;
782 0 : }
783 200 : case fd_system_program_instruction_enum_upgrade_nonce_account: {
784 : // https://github.com/solana-labs/solana/blob/b00d18cec4011bb452e3fe87a3412a3f0146942e/runtime/src/system_instruction_processor.rs#L491
785 200 : result = fd_system_program_exec_upgrade_nonce_account( ctx );
786 200 : break;
787 0 : }
788 0 : case fd_system_program_instruction_enum_create_account_allow_prefund: {
789 : // https://github.com/anza-xyz/agave/blob/v4.0.0-beta.2/programs/system/src/system_processor.rs#L530-L563
790 0 : result = fd_system_program_exec_create_account_allow_prefund(
791 0 : ctx, &instruction->inner.create_account_allow_prefund );
792 0 : break;
793 0 : }
794 3968 : }
795 :
796 3969 : return result;
797 3968 : }
798 :
799 : /**********************************************************************/
800 : /* Public API */
801 : /**********************************************************************/
802 :
803 : int
804 4097 : fd_get_system_account_kind( fd_account_meta_t const * meta ) {
805 : /* https://github.com/anza-xyz/solana-sdk/blob/nonce-account%40v2.2.1/nonce-account/src/lib.rs#L56 */
806 4097 : if( FD_UNLIKELY( memcmp( meta->owner, fd_solana_system_program_id.uc, sizeof(fd_pubkey_t) ) ) ) {
807 5 : return FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN;
808 5 : }
809 :
810 : /* https://github.com/anza-xyz/solana-sdk/blob/nonce-account%40v2.2.1/nonce-account/src/lib.rs#L57-L58 */
811 4092 : if( FD_LIKELY( !meta->dlen ) ) {
812 4065 : return FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_SYSTEM;
813 4065 : }
814 :
815 : /* https://github.com/anza-xyz/solana-sdk/blob/nonce-account%40v2.2.1/nonce-account/src/lib.rs#L59 */
816 27 : if( FD_UNLIKELY( meta->dlen!=FD_SYSTEM_PROGRAM_NONCE_DLEN ) ) {
817 1 : return FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN;
818 1 : }
819 :
820 : /* https://github.com/anza-xyz/solana-sdk/blob/nonce-account%40v2.2.1/nonce-account/src/lib.rs#L60-L64 */
821 26 : fd_nonce_state_versions_t versions[1];
822 26 : if( FD_UNLIKELY( !fd_bincode_decode_static(
823 26 : nonce_state_versions, versions,
824 26 : fd_account_data( meta ),
825 26 : meta->dlen ) ) ) {
826 2 : return FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN;
827 2 : }
828 :
829 24 : fd_nonce_state_t * state = NULL;
830 24 : if( fd_nonce_state_versions_is_current( versions ) ) {
831 21 : state = &versions->inner.current;
832 21 : } else {
833 3 : state = &versions->inner.legacy;
834 3 : }
835 :
836 24 : if( FD_LIKELY( fd_nonce_state_is_initialized( state ) ) ) {
837 21 : return FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_NONCE;
838 21 : }
839 :
840 3 : return FD_SYSTEM_PROGRAM_NONCE_ACCOUNT_KIND_UNKNOWN;
841 24 : }
|