Skip to content

SIMD-0339: Increase CPI Account Infos Limit#8513

Merged
nbelenkov merged 31 commits into
anza-xyz:masterfrom
nbelenkov:increase_cpi_info_account_limit
Oct 28, 2025
Merged

SIMD-0339: Increase CPI Account Infos Limit#8513
nbelenkov merged 31 commits into
anza-xyz:masterfrom
nbelenkov:increase_cpi_info_account_limit

Conversation

@nbelenkov
Copy link
Copy Markdown

@nbelenkov nbelenkov commented Oct 16, 2025

Problem

Adding SIMD-0339 functionality

Summary of Changes

  • Feature gate added called increase_cpi_info_account_limit
  • Max CPI account infos is now increased to 255 info accounts inclusive
  • Base cost of CPI invocation is lowered from 1000 to 946, to allow for per byte charging of account_info and ix_account_metadata.

Questions/still to do:

  • Integration tests have some info account sizes hardcoded, I couldn't work out how to pass a constant into the integration test

@nbelenkov nbelenkov requested a review from a team as a code owner October 16, 2025 11:59
Comment thread feature-set/src/lib.rs Outdated
solana_pubkey::declare_id!("8MhfKhoZEoiySpVe248bDkisyEcBA7JQLyUS94xoTSqN");
}

pub mod increase_cpi_info_account_limit {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably meant AccountInfo not "info account".

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean change it to increase_cpi_account_info_limit?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Comment thread program-runtime/src/cpi.rs Outdated
//sizeof(AccountInfo) is 80 bytes
let account_infos_bytes = account_infos
.len()
.saturating_mul(80);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just insert std::mem::sizeof::<AccountInfo>() then

Copy link
Copy Markdown
Author

@nbelenkov nbelenkov Oct 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::mem::size_of::<AccountInfo>() returns 48, because it contains references to the 2 Pubkey of owner and key, so that's why I didn't use it. The comment is a bit misleading I will update it

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ended up using base type to allign with the other calculation and adjusting it to 80 bytes, its a bit messy though

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since 80 bytes is not really correlated with the size of AccountInfo, this should just be a constant.

Comment thread program-runtime/src/cpi.rs Outdated
consume_compute_meter(
invoke_context,
(account_infos_bytes as u64)
.checked_div(invoke_context.get_execution_cost().cpi_bytes_per_unit)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would rather have this combined with the consume_compute_meter() call below.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean do the compute unit consumption inside translate_accounts_common()? Or did you mean to combine the 2 in translate_instruction_rust()?

Comment thread program-runtime/src/cpi.rs Outdated
if invoke_context.get_feature_set().increase_cpi_info_account_limit {
INVOKE_UNITS_COST_SIMD_0339
} else {
invoke_context.get_execution_cost().invoke_units
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be feature gated in ComputeBudget not here. See

pub fn new_with_defaults(simd_0268_active: bool) -> Self {
for an example of a similar feature gate there.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, this should be in the right place now

Comment thread programs/sbf/c/src/invoke/invoke.c Outdated
static const uint8_t TEST_DUPLICATE_PRIVILEGE_ESCALATION_SIGNER = 20;
static const uint8_t TEST_DUPLICATE_PRIVILEGE_ESCALATION_WRITABLE = 21;
static const uint8_t TEST_MAX_ACCOUNT_INFOS_EXCEEDED = 22;
static const uint8_t TEST_MAX_ACCOUNT_INFOS_EXCEEDED_INCREASE_CPI_INFO = 22;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally we try to prepare the code base for an easy cleanup of the feature gates, so everything is named from the perspective of the "new normal". Thus, this should stay TEST_MAX_ACCOUNT_INFOS_EXCEEDED and the other one would be TEST_MAX_ACCOUNT_INFOS_EXCEEDED_BEFORE_INCREASE or something like that.

Copy link
Copy Markdown
Author

@nbelenkov nbelenkov Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohhhh I see what you mean, so now with feature gate enabled is the new norm, hence the previous tests become before the norm right? So we would have the following for example:

TEST_MAX_ACCOUNT_INFOS_SIMD_0339_OK -> new normal ok so TEST_MAX_ACCOUNT_INFOS_OK TEST_MAX_ACCOUNT_INFOS_OK -> the original ok test so, TEST_MAX_ACCOUNT_INFOS_OK_BEFORE_CPI_INCREASE_BEFORE_SIMD_0339

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be updated now

Comment thread program-runtime/src/cpi.rs Outdated
Comment on lines +547 to +551
if invoke_context.get_feature_set().increase_cpi_info_account_limit{
// Each account meta is 34 bytes (32 for pubkey, 1 for is_signer, 1 for is_writable)
let account_meta_bytes = account_metas
.len()
.saturating_mul(34);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe you can use size_of::<AccountMeta>() here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, will update

@LucasSte
Copy link
Copy Markdown

Run cargo +nightly fmt --all to format your code after your changes.

Comment on lines 163 to 173
let max_cpi_account_infos = if invoke_context
.get_feature_set()
.increase_tx_account_lock_limit
.increase_cpi_account_info_limit
{
MAX_CPI_ACCOUNT_INFOS_SIMD_0339
} else if invoke_context
.get_feature_set()
.increase_tx_account_lock_limit
{
MAX_CPI_ACCOUNT_INFOS
} else {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two feature gates conflict with each other. Is SIMD-0339 supposed to supersede increase_tx_account_lock_limit ?

Copy link
Copy Markdown
Author

@nbelenkov nbelenkov Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's my understanding of how this SIMD-0339 should behave, see here solana-foundation/solana-improvement-documents#339 (comment). But would leave it to @jstarry to confirm

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, SIMD-0339 will override the increase_tx_account_lock_limit feature here

Comment thread program-runtime/src/cpi.rs Outdated
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_bytes = ix_c.accounts_len
.saturating_mul(34);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

size_of::<AccountMeta>()?

Copy link
Copy Markdown
Author

@nbelenkov nbelenkov Oct 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah yes, good spot, I missed that one

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Oct 21, 2025

Codecov Report

❌ Patch coverage is 76.56250% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 83.3%. Comparing base (e65003d) to head (7fa3a0d).
⚠️ Report is 1727 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #8513   +/-   ##
=======================================
  Coverage    83.3%    83.3%           
=======================================
  Files         855      855           
  Lines      372188   372286   +98     
=======================================
+ Hits       310272   310364   +92     
- Misses      61916    61922    +6     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread program-runtime/src/cpi.rs Outdated
Comment on lines +609 to +611
//std::mem::size_of::<AccountInfo>() returns 48 bytes, which contains references to the 2 Pubkeys of owner and key,
//but we need the full size here so, need to add (32 + 32) bytes for Pubkey types and account for 8 + 8 bytes already existing for refence types.
//Hence adding 32 here due to 5 bytes being the padding and 11 bytes being the other data, see SIMD-0339 for calculations.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it makes sense to use std::mem::size_of::<AccountInfo>() here. The 80 bytes from the SIMD is just a sum of the sizes of pubkey, owner, data length, and lamports because these are the things that are translated from vm to host memory. I think it's better to define a constant with a comment explaining the calculation.

Copy link
Copy Markdown
Author

@nbelenkov nbelenkov Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, I do agree, it looks very messy otherwise. It works nicely for size_of::<AccountMeta>() but not here

Comment thread program-runtime/src/cpi.rs Outdated
check_aligned,
)?;

if invoke_context
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any particular reason you chose this location rather than putting the metering inside translate_account_infos after the check_account_infos call? I think that would be a better place because then we meter CU's before doing any allocation.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is a very good point, it makes sense to move it there, it also somewhat mimics the behaviour in translate_instruction_rust/c()

@jstarry jstarry changed the title [DRAFT] SIMD-0339: Increase CPI Account Info Limit SIMD-0339: Increase CPI Account Infos Limit Oct 22, 2025
Comment thread feature-set/src/lib.rs Outdated
),
(
increase_cpi_account_info_limit::id(),
"SIMD-0339: increase CPI info account limit",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This title doesn't match the SIMD

Comment thread feature-set/src/lib.rs Outdated
}

pub mod increase_cpi_account_info_limit {
solana_pubkey::declare_id!("7wM2pdjwmSXviEdsorpcBY3T4YWUPQXDMepZudub7nGQ"); // Placeholder ID HAVE TO CHANGE BEFORE USE
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you update this with a real key?

Comment thread feature-set/src/lib.rs
pub mod discard_unexpected_data_complete_shreds {
solana_pubkey::declare_id!("8MhfKhoZEoiySpVe248bDkisyEcBA7JQLyUS94xoTSqN");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is very nit picky but this doesn't look intentional, can you undo this?

Comment thread program-runtime/src/cpi.rs Outdated
consume_compute_meter(
invoke_context,
(data.len() as u64)
(total_cu_translation_cost)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summing the total data size (ix data + account meta's) before dividing by "cpi bytes per unit" could reduce the impact of rounding error.. and that behavior doesn't match the SIMD. Combining the total cost is fine, just make sure you do the division first before summing the ix_data_cost with the ix_account_meta_cost

jstarry
jstarry previously approved these changes Oct 28, 2025
@nbelenkov nbelenkov added this pull request to the merge queue Oct 28, 2025
Merged via the queue into anza-xyz:master with commit f12e46b Oct 28, 2025
44 checks passed
@nbelenkov nbelenkov deleted the increase_cpi_info_account_limit branch October 28, 2025 16:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants