Skip to content
Merged
Changes from all commits
Commits
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
128 changes: 128 additions & 0 deletions proposals/0339-increase-cpi-account-info-limit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
---
simd: '0339'
title: Increase CPI Account Infos Limit
authors:
- Justin Starry (Anza)
category: Standard
type: Core
status: Review
created: 2025-08-15
feature: (fill in with feature key and github tracking issues once accepted)
---

## Summary

Increase the maximum number of account info's for cross-program invoked (CPI)
instructions from 64 to 255 and consume compute units for serialized account
info's and instruction account meta's.

## Motivation

CPI's are restricted to a limit of 64 account info's passed to the syscall.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes, thanks for pointing it out. The increase_tx_account_lock_limit feature gate is currently only activated on devnet and it does two things:

  1. Increase tx account lock limit from 64 to 128
  2. Increase CPI account info limit from 64 to 128

SIMD-0339 should change the CPI account info limit to 255 no matter whether the increase_tx_account_lock_limit feature gate is active or not. This SIMD has nothing to do with the tx account lock limit. It's more of an acknowledgement that account info length can contain duplicates and should be allowed to be as long as the ix account length and not necessarily the same as the tx account lock limit.

This limit is burdensome for onchain programs which themselves were invoked with
more than 64 accounts because it means they cannot simply pass through the same
list of account info's that they were invoked with to another CPI syscall. They
are faced with the burden of first deduplicating the account info's and
constructing a new list before making the syscall.

This problem arises when onchain programs wrap another program (such as Jupiter)
that composes many other programs and are invoked with over 64 accounts
(including duplicates).

Along with the increasing the account info limit, start charging for both
serialized account info's and instruction account meta's to avoid abuse of
resources in CPI calls.

## New Terminology

- **Account Info:** The serialized information for each account referenced in a
CPI instruction used to read account info from the caller program.

## Detailed Design

### Maximum Account Info Length

Increase the maximum account info length imposed on CPI syscalls from **64** to
**255**. The maximum is inclusive, meaning that a list of account info's with a
length of 255 is valid.

### Account Info Cost

Consume **1 compute unit (CU)** for every `cpi_bytes_per_unit` (currently 250)
bytes of account info.

Fixed size of **80 bytes** for each `account_info` broken down as

- 32 bytes for account address
- 32 bytes for owner address
- 8 bytes for lamport balance
- 8 bytes for data length

The total cost of account info's can be computed with
`(account_info_size * account_infos_len) / cpi_bytes_per_unit` rounded down to
Copy link
Copy Markdown
Contributor

@febo febo Aug 25, 2025

Choose a reason for hiding this comment

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

Just to confirm whether the cost is for each unique account info or not. This is not very clear from the equation here. For example, if I use a slice of 255 account infos, but all of them are copies from the same one, then the runtime has only to serialize a single account payload.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

My intention was to charge a cost for each account info in the account_infos slice passed to the CPI syscall including duplicates. The runtime needs to search for the first instance of each instruction account address in the account_infos slice. So when account_infos is longer, the runtime typically needs to do more work to do the account translation step even if some of those account info's are duplicates and skipped.

the nearest CU.

Note that the SVM can skip duplicate or unused account info's but for simpler CU
accounting, each account info has the same effect on cost regardless of whether
it's actually used by the invoked instruction.

### Instruction Account Metadata Cost

Consume **1 compute unit (CU)** for every `cpi_bytes_per_unit` (currently 250)
bytes of instruction account metadata.

Fixed size of **34 bytes** for each `ix_account_metadata` broken down as

- 32 bytes for account address
- 1 byte for signer flag
- 1 byte for writable flag

The total cost of instruction account metadata can be computed with
`(ix_account_metadata_size * ix.accounts.len()) / cpi_bytes_per_unit` rounded
down to the nearest CU.

### Reduce base CPI cost

The base cost of CPI syscalls is currently set to 1000 compute units. In order
to avoid charging more CU's for existing onchain program behavior after the
activation of this feature, the base cost of CPI syscalls will decreased by 54
compute units to 946 compute units to offset the new costs.

Before this SIMD, up to 255 instruction account metadata's could be passed to a
CPI syscall. The base cost offset is therefore `255 * 34 / 250 = 34` CU's.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It currently does not make sense to pass in that many, so it probably does not happen. Realistically this should maybe assume 64 as well?

Copy link
Copy Markdown
Contributor Author

@jstarry jstarry Sep 9, 2025

Choose a reason for hiding this comment

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

It is already over 64 in the wild (see here: https://explorer.solana.com/tx/69BYATGo3SrSPBKbF5PBs36DvJUssxrFBJtXhfRkmDBrLvLapGevr3NzpKPcBTPr52tYHCkdRNbCyXpuWjMrb4n). I think it's safer to assume 255 since it's only 34 CU's


Before this SIMD, up to 64 account info's could be passed to a CPI syscall.
The base cost offset is therefore `64 * 80 / 250 = 20` CU's.

## Alternatives Considered

What alternative designs were considered and what pros/cons does this feature
have relative to them?

## Impact

Since the list of account info's passed to a CPI can now be ~4 times longer,
there will be more overhead in the SVM to map each instruction account address
to one of the account info's.

The number of allowed unique account info's remains unchanged so the maximum
amount of accounts that need to be translated for a CPI syscall has not
increased.

CPI's will consume compute units proportional to the number of account info's
and instruction accounts. This gives an extra incentive to onchain programs
to decrease the number of accounts passed to CPI's.

## Security Considerations

NA

## Drawbacks *(Optional)*

Why should we not do this?

## Backwards Compatibility *(Optional)*

The max account info length increase for CPI's and new costs will be feature
gated. Since the limit is being increased, existing behavior will not be
restricted.
Loading