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