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