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