From 9092ee3d40975f498ae68a5a60dac60c7c67af3d Mon Sep 17 00:00:00 2001 From: Tom Pointon Date: Tue, 25 Nov 2025 17:43:04 +0000 Subject: [PATCH] flamenco, vm: implement increase_cpi_account_info_limit --- src/flamenco/features/fd_features_generated.c | 8 ++++++ src/flamenco/features/fd_features_generated.h | 5 ++-- src/flamenco/features/feature_map.json | 3 +- src/flamenco/vm/fd_vm_base.h | 18 +++++++++++- src/flamenco/vm/syscall/fd_vm_syscall_cpi.c | 21 +++++++++++++- .../vm/syscall/fd_vm_syscall_cpi_common.c | 28 +++++++++++++++++-- src/flamenco/vm/test_vm_base.c | 2 ++ 7 files changed, 77 insertions(+), 8 deletions(-) diff --git a/src/flamenco/features/fd_features_generated.c b/src/flamenco/features/fd_features_generated.c index b908aa98169..9e25d1f80fe 100644 --- a/src/flamenco/features/fd_features_generated.c +++ b/src/flamenco/features/fd_features_generated.c @@ -1691,6 +1691,12 @@ fd_feature_id_t const ids[] = { .name = "poseidon_enforce_padding", .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = offsetof(fd_features_t, increase_cpi_account_info_limit)>>3, + .id = {"\xef\x31\xcf\xa8\x88\x28\x79\x55\xd9\xb1\x72\x19\xda\x33\x5d\x8e\x8b\x8f\x5e\x3f\x41\x49\xe5\x9a\x94\x65\xa6\x44\xef\x9c\xa2\xf6"}, + /* H6iVbVaDZgDphcPbcZwc5LoznMPWQfnJ1AM7L1xzqvt5 */ + .name = "increase_cpi_account_info_limit", + .cleaned_up = {UINT_MAX, UINT_MAX, UINT_MAX} }, + { .index = ULONG_MAX } }; /* TODO replace this with fd_map_perfect */ @@ -1944,6 +1950,7 @@ fd_feature_id_query( ulong prefix ) { case 0x520c5e674243fab5: return &ids[ 244 ]; case 0xf08a42c3c040e908: return &ids[ 245 ]; case 0x8c7bee4552d93e0c: return &ids[ 246 ]; + case 0x55792888a8cf31ef: return &ids[ 247 ]; default: break; } return NULL; @@ -2196,4 +2203,5 @@ FD_STATIC_ASSERT( offsetof( fd_features_t, stricter_abi_and_runtime_constraints FD_STATIC_ASSERT( offsetof( fd_features_t, account_data_direct_mapping )>>3==244UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, fix_alt_bn128_pairing_length_check )>>3==245UL, layout ); FD_STATIC_ASSERT( offsetof( fd_features_t, poseidon_enforce_padding )>>3==246UL, layout ); +FD_STATIC_ASSERT( offsetof( fd_features_t, increase_cpi_account_info_limit )>>3==247UL, 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 2223c5147e7..56c072e88f1 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 (247UL) +#define FD_FEATURE_ID_CNT (248UL) /* Feature set ID calculated from all feature names */ -#define FD_FEATURE_SET_ID (2146234083U) +#define FD_FEATURE_SET_ID (3667030906U) union fd_features { ulong f[ FD_FEATURE_ID_CNT ]; @@ -263,5 +263,6 @@ union fd_features { /* 0x520c5e674243fab5 */ ulong account_data_direct_mapping; /* 0xf08a42c3c040e908 */ ulong fix_alt_bn128_pairing_length_check; /* 0x8c7bee4552d93e0c */ ulong poseidon_enforce_padding; + /* 0x55792888a8cf31ef */ ulong increase_cpi_account_info_limit; }; }; diff --git a/src/flamenco/features/feature_map.json b/src/flamenco/features/feature_map.json index 7f8c80e808b..0d373e2ae95 100644 --- a/src/flamenco/features/feature_map.json +++ b/src/flamenco/features/feature_map.json @@ -245,5 +245,6 @@ {"name":"stricter_abi_and_runtime_constraints","pubkey":"sD3uVpaavUXQRvDXrMFCQ2CqLqnbz5mK8ttWNXbtD3r","old":"CxeBn9PVeeXbmjbNwLv6U4C6svNxnC4JX6mfkvgeMocM"}, {"name":"account_data_direct_mapping","pubkey":"DFN8MyKpQqFW31qczcahgnnxcAHQc6P94wtTEX5EP1RA","old":"9s3RKimHWS44rJcJ9P1rwCmn2TvMqtZQBmz815ZUUHqJ"}, {"name":"fix_alt_bn128_pairing_length_check","pubkey":"bnYzodLwmybj7e1HAe98yZrdJTd7we69eMMLgCXqKZm"}, - {"name":"poseidon_enforce_padding","pubkey":"poUdAqRXXsNmfqAZ6UqpjbeYgwBygbfQLEvWSqVhSnb"} + {"name":"poseidon_enforce_padding","pubkey":"poUdAqRXXsNmfqAZ6UqpjbeYgwBygbfQLEvWSqVhSnb"}, + {"name":"increase_cpi_account_info_limit","pubkey":"H6iVbVaDZgDphcPbcZwc5LoznMPWQfnJ1AM7L1xzqvt5"} ] diff --git a/src/flamenco/vm/fd_vm_base.h b/src/flamenco/vm/fd_vm_base.h index 272cb68739c..aab50bb7ee1 100644 --- a/src/flamenco/vm/fd_vm_base.h +++ b/src/flamenco/vm/fd_vm_base.h @@ -196,10 +196,26 @@ FD_PROTOTYPES_END #define FD_VM_CREATE_PROGRAM_ADDRESS_UNITS ( 1500UL) /* FD_VM_INVOKE_UNITS is the number of compute units consumed by an - invoke call (not including the cost incurred by the called program) */ + invoke call (not including the cost incurred by the called program) + https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/execution_budget.rs#L20-L21 */ #define FD_VM_INVOKE_UNITS ( 1000UL) +/* FD_VM_INVOKE_UNITS_SIMD_0339 is the number of compute units consumed by + an invoke call (not including the cost incurred by the called program) + with SIMD-0339 (increase_cpi_account_info_limit) active. + https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/execution_budget.rs#L22-L23 */ +#define FD_VM_INVOKE_UNITS_SIMD_0339 ( 946UL) + +/* SIMD-0339 uses a fixed size (80 bytes) to bill each account info: + - 32 bytes for account address + - 32 bytes for owner address + - 8 bytes for lamports + - 8 bytes for data length + https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/cpi.rs#L63-L68 + */ +#define FD_VM_ACCOUNT_INFO_BYTE_SIZE ( 80UL) + /* FD_VM_MAX_INVOKE_STACK_HEIGHT is the maximum program instruction invocation stack height. Invocation stack height starts at 1 for transaction instructions and the stack height is incremented each diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_cpi.c b/src/flamenco/vm/syscall/fd_vm_syscall_cpi.c index 924692f173f..20350f7078e 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_cpi.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_cpi.c @@ -239,13 +239,32 @@ fd_vm_prepare_instruction( fd_instr_info_t * callee_instr, https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/programs/bpf_loader/src/syscalls/cpi.rs#L1011 */ #define FD_CPI_MAX_ACCOUNT_INFOS (128UL) +#define FD_CPI_MAX_ACCOUNT_INFOS_SIMD_0339 (255UL) + /* This is just encoding what Agave says in their code comments into a compile-time check, so if anyone ever inadvertently changes one of the limits, they will have to take a look. */ FD_STATIC_ASSERT( FD_CPI_MAX_ACCOUNT_INFOS==MAX_TX_ACCOUNT_LOCKS, cpi_max_account_info ); + +/* https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/cpi.rs#L168-L180 */ static inline ulong get_cpi_max_account_infos( fd_bank_t * bank ) { - return fd_ulong_if( FD_FEATURE_ACTIVE_BANK( bank, increase_tx_account_lock_limit ), FD_CPI_MAX_ACCOUNT_INFOS, 64UL ); + if( FD_LIKELY( FD_FEATURE_ACTIVE_BANK( bank, increase_cpi_account_info_limit ) ) ) { + return FD_CPI_MAX_ACCOUNT_INFOS_SIMD_0339; + } else if( FD_LIKELY( FD_FEATURE_ACTIVE_BANK( bank, increase_tx_account_lock_limit ) ) ) { + return FD_CPI_MAX_ACCOUNT_INFOS; + } else { + return 64UL; + } +} + +/* https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/execution_budget.rs#L25-L31 */ +static inline ulong +get_cpi_invoke_unit_cost( fd_bank_t * bank ) { + return fd_ulong_if( + FD_FEATURE_ACTIVE_BANK( bank, increase_cpi_account_info_limit ), + FD_VM_INVOKE_UNITS_SIMD_0339, + FD_VM_INVOKE_UNITS ); } /* Maximum CPI instruction data size. 10 KiB was chosen to ensure that CPI diff --git a/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c b/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c index 0d070442067..f95f8505e77 100644 --- a/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c +++ b/src/flamenco/vm/syscall/fd_vm_syscall_cpi_common.c @@ -677,7 +677,8 @@ VM_SYSCALL_CPI_ENTRYPOINT( void * _vm, fd_vm_t * vm = (fd_vm_t *)_vm; - FD_VM_CU_UPDATE( vm, FD_VM_INVOKE_UNITS ); + /* https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/cpi.rs#L815-L818 */ + FD_VM_CU_UPDATE( vm, get_cpi_invoke_unit_cost( vm->instr_ctx->bank ) ); /* Translate instruction ********************************************/ /* translate_instruction is the first thing that agave does @@ -718,7 +719,20 @@ VM_SYSCALL_CPI_ENTRYPOINT( void * _vm, /* Agave consumes CU in translate_instruction https://github.com/anza-xyz/agave/blob/838c1952595809a31520ff1603a13f2c9123aa51/programs/bpf_loader/src/syscalls/cpi.rs#L445 */ if( FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, loosen_cpi_size_restriction ) ) { - FD_VM_CU_UPDATE( vm, VM_SYSCALL_CPI_INSTR_DATA_LEN( cpi_instruction ) / FD_VM_CPI_BYTES_PER_UNIT ); + ulong total_cu_translation_cost = VM_SYSCALL_CPI_INSTR_DATA_LEN( cpi_instruction ) / FD_VM_CPI_BYTES_PER_UNIT; + + /* https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/cpi.rs#L686-L699 */ + if( FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, increase_cpi_account_info_limit ) ) { + /* Agave bills the same regardless of ABI */ + ulong account_meta_translation_cost = + fd_ulong_sat_mul( + VM_SYSCALL_CPI_INSTR_ACCS_LEN( cpi_instruction ), + FD_VM_RUST_ACCOUNT_META_SIZE ) / + FD_VM_CPI_BYTES_PER_UNIT; + total_cu_translation_cost = fd_ulong_sat_add( total_cu_translation_cost, account_meta_translation_cost ); + } + + FD_VM_CU_UPDATE( vm, total_cu_translation_cost ); } /* Final checks for translate_instruction @@ -833,7 +847,15 @@ VM_SYSCALL_CPI_ENTRYPOINT( void * _vm, return FD_VM_SYSCALL_ERR_MAX_INSTRUCTION_ACCOUNT_INFOS_EXCEEDED; } - fd_pubkey_t const * acct_info_keys[ FD_CPI_MAX_ACCOUNT_INFOS ]; + /* Consume compute units proportional to the number of account infos, if + increase_cpi_account_info_limit is active. + https://github.com/anza-xyz/agave/blob/v3.1.2/program-runtime/src/cpi.rs#L968-L980 */ + if( FD_FEATURE_ACTIVE_BANK( vm->instr_ctx->bank, increase_cpi_account_info_limit ) ) { + ulong account_infos_bytes = fd_ulong_sat_mul( acct_info_cnt, VM_SYSCALL_CPI_ACC_INFO_SIZE ); + FD_VM_CU_UPDATE( vm, account_infos_bytes / FD_VM_CPI_BYTES_PER_UNIT ); + } + + fd_pubkey_t const * acct_info_keys[ FD_CPI_MAX_ACCOUNT_INFOS_SIMD_0339 ]; for( ulong acct_idx = 0UL; acct_idx < acct_info_cnt; acct_idx++ ) { /* Translate each pubkey address specified in account_infos. Failed translation should lead to an access violation and diff --git a/src/flamenco/vm/test_vm_base.c b/src/flamenco/vm/test_vm_base.c index 3ee42d636c3..506559e11e3 100644 --- a/src/flamenco/vm/test_vm_base.c +++ b/src/flamenco/vm/test_vm_base.c @@ -51,6 +51,7 @@ FD_STATIC_ASSERT( FD_VM_COMPUTE_UNIT_LIMIT == 1400 FD_STATIC_ASSERT( FD_VM_LOG_64_UNITS == 100UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_CREATE_PROGRAM_ADDRESS_UNITS == 1500UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_INVOKE_UNITS == 1000UL, vm_cu ); +FD_STATIC_ASSERT( FD_VM_INVOKE_UNITS_SIMD_0339 == 946UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_MAX_INVOKE_STACK_HEIGHT == 5UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_MAX_INSTRUCTION_TRACE_LENGTH == 64UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_SHA256_BASE_COST == 85UL, vm_cu ); @@ -60,6 +61,7 @@ FD_STATIC_ASSERT( FD_VM_MAX_CALL_DEPTH == FD_STATIC_ASSERT( FD_VM_STACK_FRAME_SIZE == 4096UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_LOG_PUBKEY_UNITS == 100UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_MAX_CPI_INSTRUCTION_SIZE == 1280UL, vm_cu ); +FD_STATIC_ASSERT( FD_VM_ACCOUNT_INFO_BYTE_SIZE == 80UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_CPI_BYTES_PER_UNIT == 250UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_SYSVAR_BASE_COST == 100UL, vm_cu ); FD_STATIC_ASSERT( FD_VM_SECP256K1_RECOVER_COST == 25000UL, vm_cu );