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