@@ -81,36 +81,54 @@ typedef struct fd_native_prog_info fd_native_prog_info_t;
81
81
#undef PERFECT_HASH
82
82
83
83
#define MAP_PERFECT_NAME fd_native_precompile_program_fn_lookup_tbl
84
- #define MAP_PERFECT_LG_TBL_SZ 4
84
+ #define MAP_PERFECT_LG_TBL_SZ 2
85
85
#define MAP_PERFECT_T fd_native_prog_info_t
86
- #define MAP_PERFECT_HASH_C 478U
86
+ #define MAP_PERFECT_HASH_C 63546U
87
87
#define MAP_PERFECT_KEY key.uc
88
88
#define MAP_PERFECT_KEY_T fd_pubkey_t const *
89
89
#define MAP_PERFECT_ZERO_KEY (0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0)
90
90
#define MAP_PERFECT_COMPLEX_KEY 1
91
91
#define MAP_PERFECT_KEYS_EQUAL (k1 ,k2 ) (!memcmp( (k1), (k2), 32UL ))
92
92
93
- #define PERFECT_HASH ( u ) (((MAP_PERFECT_HASH_C*(u))>>28)&0xFU )
93
+ #define PERFECT_HASH ( u ) (((MAP_PERFECT_HASH_C*(u))>>30)&0x3U )
94
94
95
95
#define MAP_PERFECT_HASH_PP ( a00 ,a01 ,a02 ,a03 ,a04 ,a05 ,a06 ,a07 ,a08 ,a09 ,a10 ,a11 ,a12 ,a13 ,a14 ,a15 , \
96
96
a16 ,a17 ,a18 ,a19 ,a20 ,a21 ,a22 ,a23 ,a24 ,a25 ,a26 ,a27 ,a28 ,a29 ,a30 ,a31 ) \
97
- PERFECT_HASH( (a08 | (a09 <<8) | (a10<<16) | (a11<<24 )) )
98
- #define MAP_PERFECT_HASH_R ( ptr ) PERFECT_HASH( fd_uint_load_4 ( (uchar const *)ptr + 8UL ) )
97
+ PERFECT_HASH( (a00 | (a01 <<8)) )
98
+ #define MAP_PERFECT_HASH_R ( ptr ) PERFECT_HASH( fd_uint_load_2 ( (uchar const *)ptr ) )
99
99
100
- #define MAP_PERFECT_0 ( ED25519_SV_PROG_ID ), .fn = fd_precompile_ed25519_execute
101
- #define MAP_PERFECT_1 ( KECCAK_SECP_PROG_ID ), .fn = fd_precompile_secp256k1_execute
102
- #define MAP_PERFECT_2 ( SECP256R1_PROG_ID ), .fn = fd_precompile_secp256r1_execute
100
+ #define MAP_PERFECT_0 ( ED25519_SV_PROG_ID ), .fn = fd_precompile_ed25519_verify
101
+ #define MAP_PERFECT_1 ( KECCAK_SECP_PROG_ID ), .fn = fd_precompile_secp256k1_verify
102
+ #define MAP_PERFECT_2 ( SECP256R1_PROG_ID ), .fn = fd_precompile_secp256r1_verify
103
103
104
104
#include "../../util/tmpl/fd_map_perfect.c"
105
105
#undef PERFECT_HASH
106
106
107
- /* https://github.com/anza-xyz/agave/blob/v2.2.6/program-runtime/src/invoke_context.rs#L520-L544 */
108
- int
107
+ fd_exec_instr_fn_t
108
+ fd_executor_lookup_native_precompile_program ( fd_txn_account_t const * prog_acc ) {
109
+ fd_pubkey_t const * pubkey = prog_acc -> pubkey ;
110
+ const fd_native_prog_info_t null_function = {0 };
111
+ return fd_native_precompile_program_fn_lookup_tbl_query ( pubkey , & null_function )-> fn ;
112
+ }
113
+
114
+ /* fd_executor_lookup_native_program returns the appropriate instruction processor for the given
115
+ native program ID. Returns NULL if given ID is not a recognized native program.
116
+ https://github.com/anza-xyz/agave/blob/v2.2.6/program-runtime/src/invoke_context.rs#L520-L544 */
117
+ static int
109
118
fd_executor_lookup_native_program ( fd_txn_account_t const * prog_acc ,
110
119
fd_exec_txn_ctx_t * txn_ctx ,
111
- fd_exec_instr_fn_t * native_prog_fn ) {
112
- fd_pubkey_t const * pubkey = prog_acc -> pubkey ;
113
- fd_pubkey_t const * owner = prog_acc -> vt -> get_owner ( prog_acc );
120
+ fd_exec_instr_fn_t * native_prog_fn ,
121
+ uchar * is_precompile ) {
122
+ /* First lookup to see if the program key is a precompile */
123
+ * is_precompile = 0 ;
124
+ * native_prog_fn = fd_executor_lookup_native_precompile_program ( prog_acc );
125
+ if ( FD_UNLIKELY ( * native_prog_fn != NULL ) ) {
126
+ * is_precompile = 1 ;
127
+ return 0 ;
128
+ }
129
+
130
+ fd_pubkey_t const * pubkey = prog_acc -> pubkey ;
131
+ fd_pubkey_t const * owner = prog_acc -> vt -> get_owner ( prog_acc );
114
132
115
133
/* Native programs should be owned by the native loader...
116
134
This will not be the case though once core programs are migrated to BPF. */
@@ -125,25 +143,12 @@ fd_executor_lookup_native_program( fd_txn_account_t const * prog_acc,
125
143
}
126
144
}
127
145
128
- if ( FD_UNLIKELY ( !memcmp ( pubkey , fd_solana_ed25519_sig_verify_program_id .key , sizeof (fd_pubkey_t ) ) &&
129
- !memcmp ( owner , fd_solana_system_program_id .key , sizeof (fd_pubkey_t ) ) ) ) {
130
- /* ... except for the special case for testnet ed25519, which is
131
- bizarrely owned by the system program. */
132
- is_native_program = 1 ;
133
- }
134
- fd_pubkey_t const * lookup_pubkey = is_native_program ? pubkey : owner ;
135
- const fd_native_prog_info_t null_function = {0 };
146
+ fd_pubkey_t const * lookup_pubkey = is_native_program ? pubkey : owner ;
147
+ fd_native_prog_info_t const null_function = {0 };
136
148
* native_prog_fn = fd_native_program_fn_lookup_tbl_query ( lookup_pubkey , & null_function )-> fn ;
137
149
return 0 ;
138
150
}
139
151
140
- fd_exec_instr_fn_t
141
- fd_executor_lookup_native_precompile_program ( fd_txn_account_t const * prog_acc ) {
142
- fd_pubkey_t const * pubkey = prog_acc -> pubkey ;
143
- const fd_native_prog_info_t null_function = {0 };
144
- return fd_native_precompile_program_fn_lookup_tbl_query ( pubkey , & null_function )-> fn ;
145
- }
146
-
147
152
/* Returns 1 if the sysvar instruction is used, 0 otherwise */
148
153
uint
149
154
fd_executor_txn_uses_sysvar_instructions ( fd_exec_txn_ctx_t const * txn_ctx ) {
@@ -336,35 +341,50 @@ fd_executor_check_transactions( fd_exec_txn_ctx_t * txn_ctx ) {
336
341
/* https://github.com/anza-xyz/agave/blob/v2.1.0/runtime/src/verify_precompiles.rs#L11-L34 */
337
342
int
338
343
fd_executor_verify_precompiles ( fd_exec_txn_ctx_t * txn_ctx ) {
339
- ushort instr_cnt = txn_ctx -> txn_descriptor -> instr_cnt ;
340
- fd_acct_addr_t const * tx_accs = fd_txn_get_acct_addrs ( txn_ctx -> txn_descriptor , txn_ctx -> _txn_raw -> raw ) ;
341
- int err = 0 ;
344
+ ushort instr_cnt = txn_ctx -> txn_descriptor -> instr_cnt ;
345
+ int err = 0 ;
346
+
342
347
for ( ushort i = 0 ; i < instr_cnt ; i ++ ) {
343
- fd_txn_instr_t const * instr = & txn_ctx -> txn_descriptor -> instr [i ];
344
- fd_acct_addr_t const * program_id = tx_accs + instr -> program_id ;
345
- if ( !memcmp ( program_id , & fd_solana_ed25519_sig_verify_program_id , sizeof (fd_pubkey_t ) ) ) {
346
- err = fd_precompile_ed25519_verify ( txn_ctx , instr );
347
- if ( FD_UNLIKELY ( err ) ) {
348
- FD_TXN_ERR_FOR_LOG_INSTR ( txn_ctx , err , i );
349
- return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ;
350
- }
351
- } else if ( !memcmp ( program_id , & fd_solana_keccak_secp_256k_program_id , sizeof (fd_pubkey_t ) )) {
352
- err = fd_precompile_secp256k1_verify ( txn_ctx , instr );
353
- if ( FD_UNLIKELY ( err ) ) {
354
- FD_TXN_ERR_FOR_LOG_INSTR ( txn_ctx , err , i );
355
- return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ;
356
- }
357
- } else if ( !memcmp ( program_id , & fd_solana_secp256r1_program_id , sizeof (fd_pubkey_t )) && FD_FEATURE_ACTIVE ( txn_ctx -> slot , txn_ctx -> features , enable_secp256r1_precompile ) ) {
358
- err = fd_precompile_secp256r1_verify ( txn_ctx , instr );
359
- if ( FD_UNLIKELY ( err ) ) {
360
- FD_TXN_ERR_FOR_LOG_INSTR ( txn_ctx , err , i );
361
- return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ;
362
- }
348
+ fd_instr_info_t const * instr = & txn_ctx -> instr_infos [i ];
349
+ fd_txn_account_t const * program_acc = & txn_ctx -> accounts [ instr -> program_id ];
350
+ fd_exec_instr_fn_t precompile_fn = fd_executor_lookup_native_precompile_program ( program_acc );
351
+
352
+ /* We need to handle feature-gated precompiles here as well since they're not accounted for in the precompile lookup table. */
353
+ if ( FD_LIKELY ( precompile_fn == NULL ||
354
+ ( !memcmp ( program_acc -> pubkey -> key , & fd_solana_secp256r1_program_id .key , sizeof (fd_pubkey_t ) ) &&
355
+ !FD_FEATURE_ACTIVE ( txn_ctx -> slot , txn_ctx -> features , enable_secp256r1_precompile ) ) ) ) {
356
+ continue ;
357
+ }
358
+
359
+ /* We can create a mock instr_ctx since we only need the txn_ctx and instr fields */
360
+ fd_exec_instr_ctx_t instr_ctx = {
361
+ .txn_ctx = txn_ctx ,
362
+ .instr = instr ,
363
+ };
364
+
365
+ err = precompile_fn ( & instr_ctx );
366
+ if ( FD_UNLIKELY ( err ) ) {
367
+ FD_TXN_ERR_FOR_LOG_INSTR ( txn_ctx , err , i );
368
+ return FD_RUNTIME_TXN_ERR_INSTRUCTION_ERROR ;
363
369
}
364
370
}
371
+
365
372
return FD_RUNTIME_EXECUTE_SUCCESS ;
366
373
}
367
374
375
+ static void
376
+ fd_executor_setup_instr_infos_from_txn_instrs ( fd_exec_txn_ctx_t * txn_ctx ) {
377
+ ushort instr_cnt = txn_ctx -> txn_descriptor -> instr_cnt ;
378
+
379
+ /* Set up the instr infos for the transaction */
380
+ for ( ushort i = 0 ; i < instr_cnt ; i ++ ) {
381
+ fd_txn_instr_t const * instr = & txn_ctx -> txn_descriptor -> instr [i ];
382
+ fd_instr_info_init_from_txn_instr ( & txn_ctx -> instr_infos [i ], txn_ctx , instr );
383
+ }
384
+
385
+ txn_ctx -> instr_info_cnt = instr_cnt ;
386
+ }
387
+
368
388
/* https://github.com/anza-xyz/agave/blob/v2.0.9/svm/src/account_loader.rs#L410-427 */
369
389
static int
370
390
accumulate_and_check_loaded_account_data_size ( ulong acc_size ,
@@ -432,18 +452,9 @@ load_transaction_account( fd_exec_txn_ctx_t * txn_ctx,
432
452
https://github.com/anza-xyz/agave/blob/v2.2.0/svm/src/account_loader.rs#L393-L534 */
433
453
int
434
454
fd_executor_load_transaction_accounts ( fd_exec_txn_ctx_t * txn_ctx ) {
435
- ulong requested_loaded_accounts_data_size = txn_ctx -> loaded_accounts_data_size_limit ;
436
- ushort instr_cnt = txn_ctx -> txn_descriptor -> instr_cnt ;
437
-
438
- /* Set up the instr infos for the transaction */
439
- for ( ushort i = 0 ; i < instr_cnt ; i ++ ) {
440
- fd_txn_instr_t const * instr = & txn_ctx -> txn_descriptor -> instr [i ];
441
- fd_instr_info_init_from_txn_instr ( & txn_ctx -> instr_infos [i ], txn_ctx , instr );
442
- }
443
- txn_ctx -> instr_info_cnt = txn_ctx -> txn_descriptor -> instr_cnt ;
444
-
445
- fd_epoch_schedule_t const * schedule = fd_sysvar_cache_epoch_schedule ( txn_ctx -> sysvar_cache );
446
- ulong epoch = fd_slot_to_epoch ( schedule , txn_ctx -> slot , NULL );
455
+ ulong requested_loaded_accounts_data_size = txn_ctx -> loaded_accounts_data_size_limit ;
456
+ fd_epoch_schedule_t const * schedule = fd_sysvar_cache_epoch_schedule ( txn_ctx -> sysvar_cache );
457
+ ulong epoch = fd_slot_to_epoch ( schedule , txn_ctx -> slot , NULL );
447
458
448
459
/* https://github.com/anza-xyz/agave/blob/v2.2.0/svm/src/account_loader.rs#L429-L443 */
449
460
for ( ushort i = 0 ; i < txn_ctx -> accounts_cnt ; i ++ ) {
@@ -481,6 +492,7 @@ fd_executor_load_transaction_accounts( fd_exec_txn_ctx_t * txn_ctx ) {
481
492
}
482
493
483
494
/* TODO: Consider using a hash set (if its more performant) */
495
+ ushort instr_cnt = txn_ctx -> txn_descriptor -> instr_cnt ;
484
496
fd_pubkey_t validated_loaders [instr_cnt ];
485
497
ushort validated_loaders_cnt = 0 ;
486
498
@@ -1065,28 +1077,42 @@ fd_execute_instr( fd_exec_txn_ctx_t * txn_ctx,
1065
1077
.stack_height = txn_ctx -> instr_stack_sz ,
1066
1078
};
1067
1079
1068
- /* Lookup whether the program is a native precompiled program first
1080
+ /* Look up the native program. We check for precompiles within the lookup function as well.
1069
1081
https://github.com/anza-xyz/agave/blob/v2.1.6/svm/src/message_processor.rs#L88 */
1070
- fd_exec_instr_fn_t native_prog_fn = fd_executor_lookup_native_precompile_program ( & txn_ctx -> accounts [ instr -> program_id ] );
1082
+ fd_exec_instr_fn_t native_prog_fn ;
1083
+ uchar is_precompile ;
1084
+ int err = fd_executor_lookup_native_program ( & txn_ctx -> accounts [ instr -> program_id ],
1085
+ txn_ctx ,
1086
+ & native_prog_fn ,
1087
+ & is_precompile );
1071
1088
1072
- if ( FD_LIKELY ( native_prog_fn == NULL ) ) {
1073
- /* Lookup a native builtin program if the program is not a precompiled program */
1074
- int err = fd_executor_lookup_native_program ( & txn_ctx -> accounts [ instr -> program_id ], txn_ctx , & native_prog_fn );
1075
- if ( FD_UNLIKELY ( err ) ) {
1076
- FD_TXN_PREPARE_ERR_OVERWRITE ( txn_ctx );
1077
- FD_TXN_ERR_FOR_LOG_INSTR ( txn_ctx , err , txn_ctx -> instr_err_idx );
1078
- return err ;
1079
- }
1080
- /* Only reset the return data when executing a native builtin program (not a precompile)
1081
- https://github.com/anza-xyz/agave/blob/v2.1.6/program-runtime/src/invoke_context.rs#L536-L537 */
1082
- fd_exec_txn_ctx_reset_return_data ( txn_ctx );
1089
+ if ( FD_UNLIKELY ( err ) ) {
1090
+ FD_TXN_PREPARE_ERR_OVERWRITE ( txn_ctx );
1091
+ FD_TXN_ERR_FOR_LOG_INSTR ( txn_ctx , err , txn_ctx -> instr_err_idx );
1092
+ return err ;
1083
1093
}
1084
1094
1085
- if ( FD_LIKELY ( native_prog_fn != NULL ) ) {
1086
- /* Log program invokation (internally caches program_id base58) */
1095
+ if ( FD_LIKELY ( native_prog_fn != NULL ) ) {
1096
+ /* If this branch is taken, we've found an entrypoint to execute. */
1087
1097
fd_log_collector_program_invoke ( ctx );
1088
- instr_exec_result = native_prog_fn ( ctx );
1098
+
1099
+ /* Only reset the return data when executing a native builtin program (not a precompile)
1100
+ https://github.com/anza-xyz/agave/blob/v2.1.6/program-runtime/src/invoke_context.rs#L536-L537 */
1101
+ if ( FD_LIKELY ( !is_precompile ) ) {
1102
+ fd_exec_txn_ctx_reset_return_data ( txn_ctx );
1103
+ }
1104
+
1105
+ /* Unconditionally execute the native program if precompile verification has been moved to svm,
1106
+ or if the native program is not a precompile */
1107
+ if ( FD_LIKELY ( FD_FEATURE_ACTIVE ( txn_ctx -> slot , txn_ctx -> features , move_precompile_verification_to_svm ) ||
1108
+ !is_precompile ) ) {
1109
+ instr_exec_result = native_prog_fn ( ctx );
1110
+ } else {
1111
+ /* The precompile was already executed at the transaction level, return success */
1112
+ instr_exec_result = FD_EXECUTOR_INSTR_SUCCESS ;
1113
+ }
1089
1114
} else {
1115
+ /* Unknown program */
1090
1116
instr_exec_result = FD_EXECUTOR_INSTR_ERR_UNSUPPORTED_PROGRAM_ID ;
1091
1117
}
1092
1118
@@ -1257,6 +1283,9 @@ fd_executor_setup_accounts_for_txn( fd_exec_txn_ctx_t * txn_ctx ) {
1257
1283
1258
1284
txn_ctx -> nonce_account_idx_in_txn = ULONG_MAX ;
1259
1285
txn_ctx -> executable_cnt = j ;
1286
+
1287
+ /* Set up instr infos from the txn descriptor. No Agave equivalent to this function. */
1288
+ fd_executor_setup_instr_infos_from_txn_instrs ( txn_ctx );
1260
1289
}
1261
1290
1262
1291
/* Stuff to be done before multithreading can begin */
0 commit comments