diff --git a/src/flamenco/features/fd_features_generated.c b/src/flamenco/features/fd_features_generated.c index 6f6d48c9996..e18f4222a63 100644 --- a/src/flamenco/features/fd_features_generated.c +++ b/src/flamenco/features/fd_features_generated.c @@ -1703,6 +1703,12 @@ fd_feature_id_t const ids[] = { .name = "provide_instruction_data_offset_in_vm_r2", .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = offsetof(fd_features_t, static_instruction_limit)>>3, + .id = {"\x4b\x3e\xa0\x91\xa9\xb6\xb5\xda\x05\x3a\x32\x6f\x7c\x18\xd9\x0d\x60\x87\x99\x76\xfb\xc6\x6f\x18\xc1\xfa\x37\x38\x94\x41\xc1\xf9"}, + /* 64ixypL1HPu8WtJhNSMb9mSgfFaJvsANuRkTbHyuLfnx */ + .name = "static_instruction_limit", + .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = ULONG_MAX } }; /* TODO replace this with fd_map_perfect */ @@ -1958,6 +1964,7 @@ fd_feature_id_query( ulong prefix ) { case 0x8c7bee4552d93e0c: return &ids[ 246 ]; case 0x866094bbfe00a7c6: return &ids[ 247 ]; case 0x7c4802b8ba3fa849: return &ids[ 248 ]; + case 0xdab5b6a991a03e4b: return &ids[ 249 ]; default: break; } return NULL; @@ -2212,4 +2219,5 @@ FD_STATIC_ASSERT( offsetof( fd_features_t, fix_alt_bn128_pairing_length_check FD_STATIC_ASSERT( offsetof( fd_features_t, poseidon_enforce_padding )>>3==246UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, relax_intrabatch_account_locks )>>3==247UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, provide_instruction_data_offset_in_vm_r2 )>>3==248UL, layout ); +FD_STATIC_ASSERT( offsetof( fd_features_t, static_instruction_limit )>>3==249UL, layout ); FD_STATIC_ASSERT( sizeof( fd_features_t )>>3==FD_FEATURE_ID_CNT, layout ); diff --git a/src/flamenco/features/fd_features_generated.h b/src/flamenco/features/fd_features_generated.h index 75e7929bc5c..d20d9e3832a 100644 --- a/src/flamenco/features/fd_features_generated.h +++ b/src/flamenco/features/fd_features_generated.h @@ -8,10 +8,10 @@ #endif /* FEATURE_ID_CNT is the number of features in ids */ -#define FD_FEATURE_ID_CNT (249UL) +#define FD_FEATURE_ID_CNT (250UL) /* Feature set ID calculated from all feature names */ -#define FD_FEATURE_SET_ID (4167120720U) +#define FD_FEATURE_SET_ID (3098242546U) union fd_features { ulong f[ FD_FEATURE_ID_CNT ]; @@ -265,5 +265,6 @@ union fd_features { /* 0x8c7bee4552d93e0c */ ulong poseidon_enforce_padding; /* 0x866094bbfe00a7c6 */ ulong relax_intrabatch_account_locks; /* 0x7c4802b8ba3fa849 */ ulong provide_instruction_data_offset_in_vm_r2; + /* 0xdab5b6a991a03e4b */ ulong static_instruction_limit; }; }; diff --git a/src/flamenco/features/feature_map.json b/src/flamenco/features/feature_map.json index 5c8aff49a7f..206ad2336ae 100644 --- a/src/flamenco/features/feature_map.json +++ b/src/flamenco/features/feature_map.json @@ -247,5 +247,6 @@ {"name":"fix_alt_bn128_pairing_length_check","pubkey":"bnYzodLwmybj7e1HAe98yZrdJTd7we69eMMLgCXqKZm"}, {"name":"poseidon_enforce_padding","pubkey":"poUdAqRXXsNmfqAZ6UqpjbeYgwBygbfQLEvWSqVhSnb"}, {"name":"relax_intrabatch_account_locks","pubkey":"ENTRYnPAoT5Swwx73YDGzMp3XnNH1kxacyvLosRHza1i"}, - {"name":"provide_instruction_data_offset_in_vm_r2","pubkey":"5xXZc66h4UdB6Yq7FzdBxBiRAFMMScMLwHxk2QZDaNZL"} + {"name":"provide_instruction_data_offset_in_vm_r2","pubkey":"5xXZc66h4UdB6Yq7FzdBxBiRAFMMScMLwHxk2QZDaNZL"}, + {"name":"static_instruction_limit","pubkey":"64ixypL1HPu8WtJhNSMb9mSgfFaJvsANuRkTbHyuLfnx"} ] diff --git a/src/flamenco/runtime/Local.mk b/src/flamenco/runtime/Local.mk index 5ed3ff78baa..9c97c236f09 100644 --- a/src/flamenco/runtime/Local.mk +++ b/src/flamenco/runtime/Local.mk @@ -55,6 +55,8 @@ ifdef FD_HAS_HOSTED ifdef FD_HAS_SECP256K1 $(call make-unit-test,test_bank,test_bank,fd_flamenco fd_funk fd_ballet fd_util) $(call run-unit-test,test_bank,) +$(call make-unit-test,test_static_instruction_limit,test_static_instruction_limit,fd_flamenco fd_funk fd_ballet fd_util) +$(call run-unit-test,test_static_instruction_limit,) endif endif diff --git a/src/flamenco/runtime/fd_executor.c b/src/flamenco/runtime/fd_executor.c index ec7d32d95a1..a2ffb7cc4cd 100644 --- a/src/flamenco/runtime/fd_executor.c +++ b/src/flamenco/runtime/fd_executor.c @@ -401,11 +401,18 @@ fd_executor_check_transactions( fd_runtime_t * runtime, https://github.com/anza-xyz/agave/blob/v2.3.1/runtime/src/bank.rs#L5725-L5753 */ int -fd_executor_verify_transaction( fd_bank_t * bank, +fd_executor_verify_transaction( fd_bank_t const * bank, fd_txn_in_t const * txn_in, fd_txn_out_t * txn_out ) { int err = FD_RUNTIME_EXECUTE_SUCCESS; + /* SIMD-0160: enforce static limit on number of instructions. + https://github.com/anza-xyz/agave/blob/v3.1.4/runtime/src/bank.rs#L4710-L4716 */ + if( FD_UNLIKELY( FD_FEATURE_ACTIVE_BANK( bank, static_instruction_limit ) && + TXN( txn_in->txn )->instr_cnt > FD_MAX_INSTRUCTION_TRACE_LENGTH ) ) { + return FD_RUNTIME_TXN_ERR_SANITIZE_FAILURE; + } + /* https://github.com/anza-xyz/agave/blob/v2.2.13/svm/src/transaction_processor.rs#L566-L569 */ err = fd_executor_compute_budget_program_execute_instructions( bank, txn_in, txn_out ); if( FD_UNLIKELY( err ) ) return err; diff --git a/src/flamenco/runtime/fd_executor.h b/src/flamenco/runtime/fd_executor.h index dd9e5216d08..67a99036cfe 100644 --- a/src/flamenco/runtime/fd_executor.h +++ b/src/flamenco/runtime/fd_executor.h @@ -40,7 +40,7 @@ uchar fd_executor_pubkey_is_bpf_loader( fd_pubkey_t const * pubkey ); int -fd_executor_verify_transaction( fd_bank_t * bank, +fd_executor_verify_transaction( fd_bank_t const * bank, fd_txn_in_t const * txn_in, fd_txn_out_t * txn_out ); diff --git a/src/flamenco/runtime/program/fd_builtin_programs.c b/src/flamenco/runtime/program/fd_builtin_programs.c index b2813aff5cf..4144bc5e7e7 100644 --- a/src/flamenco/runtime/program/fd_builtin_programs.c +++ b/src/flamenco/runtime/program/fd_builtin_programs.c @@ -336,7 +336,7 @@ fd_num_precompiles( void ) { } uchar -fd_is_migrating_builtin_program( fd_bank_t * bank, +fd_is_migrating_builtin_program( fd_bank_t const * bank, fd_pubkey_t const * pubkey, uchar * migrated_yet ) { *migrated_yet = 0; diff --git a/src/flamenco/runtime/program/fd_builtin_programs.h b/src/flamenco/runtime/program/fd_builtin_programs.h index ce443b88a7e..571fdd09605 100644 --- a/src/flamenco/runtime/program/fd_builtin_programs.h +++ b/src/flamenco/runtime/program/fd_builtin_programs.h @@ -95,7 +95,7 @@ fd_num_stateless_builtins( void ); | 1 | 1 | Program is a migrating builtin program id, AND has been migrated to BPF | */ uchar -fd_is_migrating_builtin_program( fd_bank_t * bank, +fd_is_migrating_builtin_program( fd_bank_t const * bank, fd_pubkey_t const * pubkey, uchar * migrated_yet ); diff --git a/src/flamenco/runtime/program/fd_compute_budget_program.c b/src/flamenco/runtime/program/fd_compute_budget_program.c index a72c4875914..78b8be858c9 100644 --- a/src/flamenco/runtime/program/fd_compute_budget_program.c +++ b/src/flamenco/runtime/program/fd_compute_budget_program.c @@ -14,7 +14,7 @@ #define MAX_BUILTIN_ALLOCATION_COMPUTE_UNIT_LIMIT (3000UL) FD_FN_PURE static inline uchar -get_program_kind( fd_bank_t * bank, +get_program_kind( fd_bank_t const * bank, fd_txn_in_t const * txn_in, fd_txn_instr_t const * instr ) { fd_acct_addr_t const * txn_accs = fd_txn_get_acct_addrs( TXN( txn_in->txn ), txn_in->txn->payload ); @@ -114,7 +114,7 @@ fd_sanitize_compute_unit_limits( fd_txn_out_t * txn_out ) { https://github.com/anza-xyz/agave/blob/v2.3.1/compute-budget-instruction/src/compute_budget_instruction_details.rs#L54-L99 */ int -fd_executor_compute_budget_program_execute_instructions( fd_bank_t * bank, +fd_executor_compute_budget_program_execute_instructions( fd_bank_t const * bank, fd_txn_in_t const * txn_in, fd_txn_out_t * txn_out ) { fd_compute_budget_details_t * details = &txn_out->details.compute_budget; diff --git a/src/flamenco/runtime/program/fd_compute_budget_program.h b/src/flamenco/runtime/program/fd_compute_budget_program.h index 650bd87ab56..aec261d8c44 100644 --- a/src/flamenco/runtime/program/fd_compute_budget_program.h +++ b/src/flamenco/runtime/program/fd_compute_budget_program.h @@ -30,7 +30,7 @@ int fd_sanitize_compute_unit_limits( fd_txn_out_t * txn_out ); int -fd_executor_compute_budget_program_execute_instructions( fd_bank_t * bank, +fd_executor_compute_budget_program_execute_instructions( fd_bank_t const * bank, fd_txn_in_t const * txn_in, fd_txn_out_t * txn_out ); diff --git a/src/flamenco/runtime/test_static_instruction_limit.c b/src/flamenco/runtime/test_static_instruction_limit.c new file mode 100644 index 00000000000..efdde4b4704 --- /dev/null +++ b/src/flamenco/runtime/test_static_instruction_limit.c @@ -0,0 +1,125 @@ +/* Test for SIMD-0160 static_instruction_limit */ + +#include "fd_executor.h" +#include "fd_bank.h" +#include "fd_runtime.h" +#include "fd_runtime_err.h" +#include "../features/fd_features.h" + +static void +init_bank( fd_bank_t * bank ) { + memset( bank, 0, sizeof(fd_bank_t) ); + fd_bank_slot_set( bank, 1UL ); +} + +static void +init_txn_with_instr_cnt( fd_txn_p_t * txn_p, + ushort instr_cnt ) { + fd_txn_t * txn = TXN( txn_p ); + + txn->transaction_version = FD_TXN_V0; + txn->instr_cnt = instr_cnt; + + for( ushort i=0; iinstr[i].program_id = 0; + txn->instr[i].acct_cnt = 0; + txn->instr[i].data_sz = 0; + txn->instr[i].acct_off = 0; + txn->instr[i].data_off = 0; + } +} + +static void +activate_static_instruction_limit( fd_bank_t * bank ) { + fd_bank_features_modify( bank )->static_instruction_limit = 0UL; +} + +static void +deactivate_static_instruction_limit( fd_bank_t * bank ) { + fd_bank_features_modify( bank )->static_instruction_limit = FD_FEATURE_DISABLED; +} + +static void +test_static_instruction_limit_deactivated( fd_bank_t * bank ) { + fd_txn_p_t txn_p[1] = {0}; + fd_txn_out_t txn_out[1] = {0}; + + init_bank( bank ); + deactivate_static_instruction_limit( bank ); + init_txn_with_instr_cnt( txn_p, 65 ); + + fd_txn_in_t txn_in = { .txn = txn_p }; + + FD_TEST( fd_executor_verify_transaction( bank, &txn_in, txn_out )==FD_RUNTIME_EXECUTE_SUCCESS ); +} + +static void +test_static_instruction_limit_exceeded( fd_bank_t * bank ) { + fd_txn_p_t txn_p[1] = {0}; + fd_txn_out_t txn_out[1] = {0}; + + init_bank( bank ); + activate_static_instruction_limit( bank ); + init_txn_with_instr_cnt( txn_p, 65 ); + + fd_txn_in_t txn_in = { .txn = txn_p }; + + FD_TEST( fd_executor_verify_transaction( bank, &txn_in, txn_out )==FD_RUNTIME_TXN_ERR_SANITIZE_FAILURE ); +} + +static void +test_static_instruction_limit_at_limit( fd_bank_t * bank ) { + fd_txn_p_t txn_p[1] = {0}; + fd_txn_out_t txn_out[1] = {0}; + + init_bank( bank ); + activate_static_instruction_limit( bank ); + init_txn_with_instr_cnt( txn_p, 64 ); + + fd_txn_in_t txn_in = { .txn = txn_p }; + + FD_TEST( fd_executor_verify_transaction( bank, &txn_in, txn_out )==FD_RUNTIME_EXECUTE_SUCCESS ); +} + +static void +test_static_instruction_limit_under_limit( fd_bank_t * bank ) { + fd_txn_p_t txn_p[1] = {0}; + fd_txn_out_t txn_out[1] = {0}; + + init_bank( bank ); + activate_static_instruction_limit( bank ); + init_txn_with_instr_cnt( txn_p, 1 ); + + fd_txn_in_t txn_in = { .txn = txn_p }; + + FD_TEST( fd_executor_verify_transaction( bank, &txn_in, txn_out )==FD_RUNTIME_EXECUTE_SUCCESS ); +} + +int +main( int argc, + char ** argv ) { + fd_boot( &argc, &argv ); + + char * _page_sz = "gigantic"; + ulong numa_idx = fd_shmem_numa_idx( 0 ); + fd_wksp_t * wksp = fd_wksp_new_anonymous( fd_cstr_to_shmem_page_sz( _page_sz ), + 1UL, + fd_shmem_cpu_idx( numa_idx ), + "wksp", + 0UL ); + FD_TEST( wksp ); + + fd_bank_t * bank = fd_wksp_alloc_laddr( wksp, alignof(fd_bank_t), sizeof(fd_bank_t), 1UL ); + FD_TEST( bank ); + + test_static_instruction_limit_deactivated( bank ); + test_static_instruction_limit_exceeded( bank ); + test_static_instruction_limit_at_limit( bank ); + test_static_instruction_limit_under_limit( bank ); + + fd_wksp_delete_anonymous( wksp ); + + FD_LOG_NOTICE(( "pass" )); + fd_halt(); + return 0; +}