Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
23f8d97
SIMD 0339 functionality + integration tests
nbelenkov Oct 16, 2025
1c9619b
Merge branch 'master' into increase_cpi_info_account_limit
nbelenkov Oct 16, 2025
2f3446d
refactor feature gate to be in ComputeBudget
nbelenkov Oct 16, 2025
12b7a09
Merge branch 'increase_cpi_info_account_limit' of github.com:nbelenko…
nbelenkov Oct 16, 2025
8a65c68
adding types for byte calculation and updated the comment
nbelenkov Oct 17, 2025
0d31630
fix missed invocation with new function signature
nbelenkov Oct 17, 2025
620ff0e
changed feature name to increase_cpi_account_info_limit
nbelenkov Oct 17, 2025
917abad
test renaming for new normal prospective + whitespace format
nbelenkov Oct 20, 2025
b0407e6
changing missed hardcoded value to type size on c account translation
nbelenkov Oct 20, 2025
01466de
fixing CI issue with whitespaces in C program
nbelenkov Oct 21, 2025
df4d61d
adding execution cost initialization to bank creation
nbelenkov Oct 21, 2025
8e3e3d1
adding CU tests
nbelenkov Oct 22, 2025
3c81a81
cargo fmt didn't work on some files
nbelenkov Oct 22, 2025
4629daa
c file whitespace
nbelenkov Oct 22, 2025
abc7e34
using test-v3 for CU estimations
nbelenkov Oct 22, 2025
c51ec8c
upper bound of CU test due to different sbpf versions
nbelenkov Oct 23, 2025
9071ea7
panic error fix
nbelenkov Oct 23, 2025
004ac03
constant for AccountInfo type size + account info charging relocation
nbelenkov Oct 23, 2025
c4b8563
merge CU consuming calls into 1
nbelenkov Oct 24, 2025
9076cff
cargo fmt
nbelenkov Oct 24, 2025
4db843a
mergin master into this PR
nbelenkov Oct 24, 2025
ac84ebd
cargo fmt the merge
nbelenkov Oct 24, 2025
3f722bd
renamed tests + cargo.lock update
nbelenkov Oct 24, 2025
bcf5f2b
Merge branch 'master' into increase_cpi_info_account_limit
nbelenkov Oct 25, 2025
634f923
updated keypair for feature gate + refactored total_cu_translation_co…
nbelenkov Oct 27, 2025
f44b4c8
Merge branch 'master' into increase_cpi_info_account_limit
nbelenkov Oct 27, 2025
c9e055d
fmt after upstream sync
nbelenkov Oct 27, 2025
171f59b
var renaming
nbelenkov Oct 27, 2025
3e71a15
Merge branch 'master' into increase_cpi_info_account_limit
nbelenkov Oct 27, 2025
4f474f5
Merge branch 'master' into increase_cpi_info_account_limit
nbelenkov Oct 28, 2025
7fa3a0d
Merge branch 'master' into increase_cpi_info_account_limit
nbelenkov Oct 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions compute-budget/src/compute_budget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ impl Default for ComputeBudget {
}

impl ComputeBudget {
pub fn new_with_defaults(simd_0268_active: bool) -> Self {
pub fn new_with_defaults(simd_0268_active: bool, simd_0339_active: bool) -> Self {
Self::from_budget_and_cost(
&SVMTransactionExecutionBudget::new_with_defaults(simd_0268_active),
&SVMTransactionExecutionCost::default(),
&SVMTransactionExecutionCost::new_with_defaults(simd_0339_active),
)
}

Expand Down
9 changes: 9 additions & 0 deletions feature-set/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ impl FeatureSet {
raise_cpi_nesting_limit_to_8: self.is_active(&raise_cpi_nesting_limit_to_8::id()),
provide_instruction_data_offset_in_vm_r2: self
.is_active(&provide_instruction_data_offset_in_vm_r2::id()),
increase_cpi_account_info_limit: self.is_active(&increase_cpi_account_info_limit::id()),
vote_state_v4: self.is_active(&vote_state_v4::id()),
}
}
Expand Down Expand Up @@ -1167,6 +1168,10 @@ pub mod switch_to_chacha8_turbine {
solana_pubkey::declare_id!("CHaChatUnR3s6cPyPMMGNJa3VdQQ8PNH2JqdD4LpCKnB");
}

pub mod increase_cpi_account_info_limit {
solana_pubkey::declare_id!("H6iVbVaDZgDphcPbcZwc5LoznMPWQfnJ1AM7L1xzqvt5");
}

pub mod deprecate_rent_exemption_threshold {
solana_pubkey::declare_id!("rent6iVy6PDoViPBeJ6k5EJQrkj62h7DPyLbWGHwjrC");
}
Expand Down Expand Up @@ -2102,6 +2107,10 @@ pub static FEATURE_NAMES: LazyLock<AHashMap<Pubkey, &'static str>> = LazyLock::n
switch_to_chacha8_turbine::id(),
"SIMD-0332: Reduce ChaCha rounds for Turbine from 20 to 8",
),
(
increase_cpi_account_info_limit::id(),
"SIMD-0339: Increase CPI Account Infos Limit",
),
(
deprecate_rent_exemption_threshold::id(),
"SIMD-0194: Deprecate rent exemption threshold",
Expand Down
89 changes: 71 additions & 18 deletions program-runtime/src/cpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ type Error = Box<dyn std::error::Error>;
const SUCCESS: u64 = 0;
/// Maximum signers
const MAX_SIGNERS: usize = 16;
///SIMD-0339 based calculation of AccountInfo translation byte size. Fixed size of **80 bytes** for each AccountInfo broken down as:
/// - 32 bytes for account address
/// - 32 bytes for owner address
/// - 8 bytes for lamport balance
/// - 8 bytes for data length
const ACCOUNT_INFO_BYTE_SIZE: usize = 80;

/// Rust representation of C's SolInstruction
#[derive(Debug)]
Expand Down Expand Up @@ -114,6 +120,8 @@ struct SolSignerSeedsC {

/// Maximum number of account info structs that can be used in a single CPI invocation
const MAX_CPI_ACCOUNT_INFOS: usize = 128;
/// Maximum number of account info structs that can be used in a single CPI invocation with SIMD-0339 active
const MAX_CPI_ACCOUNT_INFOS_SIMD_0339: usize = 255;

/// Check that an account info pointer field points to the expected address
fn check_account_info_pointer(
Expand Down Expand Up @@ -158,6 +166,11 @@ fn check_account_infos(
invoke_context: &mut InvokeContext,
) -> Result<(), Error> {
let max_cpi_account_infos = if invoke_context
.get_feature_set()
.increase_cpi_account_info_limit
{
MAX_CPI_ACCOUNT_INFOS_SIMD_0339
} else if invoke_context
.get_feature_set()
.increase_tx_account_lock_limit
{
Expand Down Expand Up @@ -531,17 +544,29 @@ pub fn translate_instruction_rust(
ix.data.as_vaddr(),
ix.data.len(),
check_aligned,
)?
.to_vec();
)?;

check_instruction_size(account_metas.len(), data.len())?;

consume_compute_meter(
invoke_context,
(data.len() as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX),
)?;
let mut total_cu_translation_cost: u64 = (data.len() as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX);

if invoke_context
.get_feature_set()
.increase_cpi_account_info_limit
{
// Each account meta is 34 bytes (32 for pubkey, 1 for is_signer, 1 for is_writable)
let account_meta_translation_cost =
(account_metas.len().saturating_mul(size_of::<AccountMeta>()) as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX);

total_cu_translation_cost =
total_cu_translation_cost.saturating_add(account_meta_translation_cost);
}

consume_compute_meter(invoke_context, total_cu_translation_cost)?;

let mut accounts = Vec::with_capacity(account_metas.len());
#[allow(clippy::needless_range_loop)]
Expand All @@ -559,7 +584,7 @@ pub fn translate_instruction_rust(

Ok(Instruction {
accounts,
data,
data: data.to_vec(),
program_id: ix.program_id,
})
}
Expand Down Expand Up @@ -650,17 +675,30 @@ pub fn translate_instruction_c(
ix_c.accounts_len,
check_aligned,
)?;
let data = translate_slice::<u8>(memory_mapping, ix_c.data_addr, ix_c.data_len, check_aligned)?
.to_vec();
let data = translate_slice::<u8>(memory_mapping, ix_c.data_addr, ix_c.data_len, check_aligned)?;

check_instruction_size(ix_c.accounts_len as usize, data.len())?;

consume_compute_meter(
invoke_context,
(data.len() as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX),
)?;
let mut total_cu_translation_cost: u64 = (data.len() as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX);

if invoke_context
.get_feature_set()
.increase_cpi_account_info_limit
{
// Each account meta is 34 bytes (32 for pubkey, 1 for is_signer, 1 for is_writable)
let account_meta_translation_cost = (ix_c
.accounts_len
.saturating_mul(size_of::<AccountMeta>() as u64))
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX);

total_cu_translation_cost =
total_cu_translation_cost.saturating_add(account_meta_translation_cost);
}

consume_compute_meter(invoke_context, total_cu_translation_cost)?;

let mut accounts = Vec::with_capacity(ix_c.accounts_len as usize);
#[allow(clippy::needless_range_loop)]
Expand All @@ -684,7 +722,7 @@ pub fn translate_instruction_c(

Ok(Instruction {
accounts,
data,
data: data.to_vec(),
program_id: *program_id,
})
}
Expand Down Expand Up @@ -926,6 +964,21 @@ where
check_aligned,
)?;
check_account_infos(account_infos.len(), invoke_context)?;

if invoke_context
.get_feature_set()
.increase_cpi_account_info_limit
{
let account_infos_bytes = account_infos.len().saturating_mul(ACCOUNT_INFO_BYTE_SIZE);

consume_compute_meter(
invoke_context,
(account_infos_bytes as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
.unwrap_or(u64::MAX),
)?;
}

let mut account_info_keys = Vec::with_capacity(account_infos_len as usize);
#[allow(clippy::needless_range_loop)]
for account_index in 0..account_infos_len as usize {
Expand Down
25 changes: 21 additions & 4 deletions program-runtime/src/execution_budget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ fn get_max_instruction_stack_depth(simd_0268_active: bool) -> usize {
}
}

//Default CPI invocation cost
pub const DEFAULT_INVOCATION_COST: u64 = 1000;
//CPI Invocation cost with SIMD-0339 active
pub const INVOKE_UNITS_COST_SIMD_0339: u64 = 946;

fn get_invoke_unit_cost(simd_0339_active: bool) -> u64 {
if simd_0339_active {
INVOKE_UNITS_COST_SIMD_0339
} else {
DEFAULT_INVOCATION_COST
}
}

/// Max call depth. This is the maximum nesting of SBF to SBF call that can happen within a program.
pub const MAX_CALL_DEPTH: usize = 64;

Expand Down Expand Up @@ -176,10 +189,16 @@ pub struct SVMTransactionExecutionCost {

impl Default for SVMTransactionExecutionCost {
fn default() -> Self {
Self {
Self::new_with_defaults(/* simd_0339_active */ false)
}
}

impl SVMTransactionExecutionCost {
pub fn new_with_defaults(simd_0339_active: bool) -> Self {
SVMTransactionExecutionCost {
log_64_units: 100,
create_program_address_units: 1500,
invoke_units: 1000,
invoke_units: get_invoke_unit_cost(simd_0339_active),
sha256_base_cost: 85,
sha256_byte_cost: 1,
log_pubkey_units: 100,
Expand Down Expand Up @@ -216,9 +235,7 @@ impl Default for SVMTransactionExecutionCost {
alt_bn128_g2_decompress: 13610,
}
}
}

impl SVMTransactionExecutionCost {
/// Returns cost of the Poseidon hash function for the given number of
/// inputs is determined by the following quadratic function:
///
Expand Down
4 changes: 3 additions & 1 deletion program-runtime/src/invoke_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -833,7 +833,9 @@ macro_rules! with_mock_invoke_context_with_feature_set {
environment_config,
Some(LogCollector::new_ref()),
compute_budget,
SVMTransactionExecutionCost::default(),
SVMTransactionExecutionCost::new_with_defaults(
$feature_set.increase_cpi_account_info_limit,
),
);
};
}
Expand Down
7 changes: 6 additions & 1 deletion program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
// Export tokio for test clients
pub use tokio;
use {
agave_feature_set::{raise_cpi_nesting_limit_to_8, FEATURE_NAMES},
agave_feature_set::{
increase_cpi_account_info_limit, raise_cpi_nesting_limit_to_8, FEATURE_NAMES,
},
async_trait::async_trait,
base64::{prelude::BASE64_STANDARD, Engine},
chrono_humanize::{Accuracy, HumanTime, Tense},
Expand Down Expand Up @@ -859,6 +861,9 @@ impl ProgramTest {
genesis_config
.accounts
.contains_key(&raise_cpi_nesting_limit_to_8::id()),
genesis_config
.accounts
.contains_key(&increase_cpi_account_info_limit::id()),
)
}),
transaction_account_lock_limit: self.transaction_account_lock_limit,
Expand Down
Loading
Loading