ABIv1 invoke signed V2 syscall
- Idea
- Draft
- Review
- Accept
- Implement
- Active
Decision brief
Why this proposal matters
This proposal introduces a new invoke syscall with an improved API to handle account information in CPI (cross-program invocation) calls, aiming to reduce the memory overhead and simplify the process of passing account data between programs and runtime.
Proposal at a glance
What changes
- This proposal introduces a new invoke syscall with an improved API to handle account information in CPI (cross-program invocation) calls, aiming to reduce the memory overhead and simplify the process of passing account data between programs and runtime.
Stakeholder map
Who is affected
Builders & client teams Medium impact
The proposal will reduce the memory overhead of CPIs, which will improve performance and reduce the likelihood of heap allocation. This will benefit program developers by making it easier to write efficient programs.
Action requirement unknownValidators & operators Medium impact
Validator Components Affected
Action requirement unknownUsers & stakers Impact unknown
No proposal-specific evidence was found for this group.
Action requirement unknownGovernance & ecosystem Medium impact
The proposal will reduce the memory overhead of CPIs, which will improve performance and reduce the likelihood of heap allocation. This will benefit program developers by making it easier to write efficient programs.
Action requirement unknownExact source revision
Full proposal document
2934dbeb1c8aSummary
This proposal introduces a new invoke syscall with an improved API to handle account information in CPI (cross-program invocation) calls, aiming to reduce the memory overhead and simplify the process of passing account data between programs and runtime.
Motivation
Currently, configuring CPI parameters in ABIv1 programs is unnecessarily cumbersome:
- It requires passing two account slices:
&[AccountMeta]and&[AccountInfo]. - It requires converting account information received as program input into a different layout, even though the runtime subsequently converts it into yet another layout.
Both requirements force programs to allocate and copy more memory than strictly
necessary. This overhead could be avoided without negatively affecting runtime
performance. An AccountMeta occupies 34 bytes, while an AccountInfo
occupies 56 bytes. Therefore, a program must manipulate 90 bytes per account
for each CPI. This often requires heap allocation because the total size can
exceed the maximum stack size of 4096 bytes, particularly given that a CPI can
accept up to 255 accounts.
New Terminology
N/A
Detailed Design
To address the first issue, we can eliminate one of the account slices by
combining the information contained in AccountMeta and AccountInfo. The
purpose of AccountMeta is to associate the writable and signer flags with an
account, while AccountInfo contains the actual account information.
The second issue can be mitigated by allowing programs to simply pass the index of the account in the instruction rather than requiring them to copy the account information into a different layout. The runtime already has access to the account information, so it can look up the account by index and retrieve the necessary information.
These two changes can be combined by defining a new type CpiAccount that
associates the account index with the writable/signer flags, reducing the
per-account memory requirement for a CPI from 90 bytes to 4 bytes.
/// Representation of an account used in a CPI.
#[repr(C)]
pub struct CpiAccount {
/// Index of the account in the current instruction.
pub account_index: u16,
/// Indicates whether the account is writable.
pub is_writable: u8,
/// Indicates whether the account signed the instruction.
pub is_signer: u8,
}
The program creates a new CpiInstruction containing a single slice of the
accounts expected by the invoked program:
/// Information about an instruction for a CPI.
#[repr(C)]
pub struct CpiInstruction {
/// Address of the program to invoke.
program_id: * const [u8; 32],
/// Accounts expected by the program instruction.
accounts: *const CpiAccount,
/// Number of accounts expected by the program instruction.
accounts_len: u64,
/// Data expected by the program instruction.
data: *const u8,
/// Length of the data expected by the program instruction.
data_len: u64,
}
Finally, the CpiInstruction is used as a parameter to a new invoke_signed_v2
syscall:
pub fn sol_invoke_signed_v2(
instruction_addr: u64,
signers_seeds_addr: u64,
signers_seeds_len: u64,
);
The layout for signer seeds is the same as in the current invoke syscall.
These modifications eliminate only the type conversions performed on the program side. The CPI logic in the runtime remains unchanged, apart from reading the account information through the instruction account index during account translation. In other words, this proposal does not change the runtime's CPI logic, but it does change the way programs pass account information to the runtime.
Validator Components Affected
Which validator components are affected by this change?
| Validator Component | Impact |
|---|---|
| Transaction Execution (Runtime) | None |
| Virtual Machine | New syscall |
| Block Packing | None |
| Consensus | None |
| Gossip | None |
| Turbine | None |
| Snapshots | None |
| On-Chain Core BPF Programs | None |
| Other (please describe) | None |
Alternatives Considered
Continue without the new syscall. This would maintain the current overhead of CPIs, which is unnecessary and inefficient.
Continue to use the existing
AccountMeta, but pass a slice of account pointers to the runtime instead ofAccountInfo. This would reduce the memory requirement from90to42bytes (34+8bytes) per account. This does not offer as much reduction in memory overhead as the proposed solution, and also still requires a second slice of accounts to be passed to the runtime.Instead of using the index of an account in the transaction, pass account pointers to the runtime. This reduces the memory requirement from
90to16bytes per account, including6bytes of padding — the program itself copies only10bytes per account. While this reduces memory overhead, the current proposal is more efficient. In particular, using account indices allows the CPI account list to be constructed statically at compile time when the program’s account list is deterministic.
Impact
The proposal will reduce the memory overhead of CPIs, which will improve performance and reduce the likelihood of heap allocation. This will benefit program developers by making it easier to write efficient programs.
Below is a benchmark showing reductions in CU usage when setting up CPI parameters in a Pinocchio program that performs a CPI to a simple program that logs the number of accounts received. This benchmark measures the improvement in CPI parameter setup. All other costs of a CPI remain the same.
| CPI (8) | CPI (16) | CPI (32) | CPI (64) | |
|---|---|---|---|---|
| invoke | 1,376 | 1,592 | 1,999 | 2,813 |
| invoke v2 (proposed) | 1,174 | 1,198 | 1,221 | 1,267 |
| Change invoke v2 vs invoke | −15% | −25% | −39% | −55% |
Security Considerations
The security surface is identical to that of the existing invoke syscall. This proposal does not change the CPI logic in the runtime, apart from accessing account information through the instruction account index during account translation. The same input validation and CU metering apply. Although the new syscall reduces the memory overhead of CPIs by representing account information in 4-byte descriptors, the CU charge remains based on 34 bytes per account, since the runtime still needs to read the same amount of account information from the transaction.
Backwards Compatibility
This proposal is fully backwards compatible. The new invoke_signed_v2 syscall
is an addition to the existing invoke_signed syscall, which remains unchanged.
Programs that do not use the new syscall will continue to function as before.
Evidence graph
Related proposals and rollout
One or more sources are unavailable.
Upstream review record
Upstream discussion & review
GitHub review is editorial context, not evidence of on-chain support, voting, or outcome.
PR #670 · merged SIMD-0670: ABIv1 invoke signed v2 syscall 9 comments and reviews · Oct 24, 2026Maybe mention the layout for signer seeds is unchanged from v1.
GitHub ↗Done in https://github.com/solana-foundation/solana-improvement-documents/pull/670/commits/13b49b6af8a341c6931669537431872b9e2c7832
GitHub ↗Thanks, topointon-jump(https://github.com/topointon-jump)! ⚠️ Status: Cannot merge yet - Missing approval from: Anza (t-nelson(https://github.com/t-nelson), steviez(https://github.com/steviez), or bw-solana(https://github.com/bw-solana))
GitHub ↗we should probably specify this a little more. Maybe mention that we keep the same 34-byte entry charge even though we're only receiving 4-byte descriptors? looks like Joe identified this during code review as well: https://github.com/anza-xyz/agave/pull/15979discussionr4283475414
GitHub ↗Added more details in 94fdbfb(https://github.com/solana-foundation/solana-improvement-documents/pull/670/commits/94fdbfb5b471c48bdca9d04746e6d40597bd470d) as suggested.
GitHub ↗✅ All approvals received! @febo, you can now merge this by commenting /merge. ✅ Status: Ready to merge
GitHub ↗/merge
GitHub ↗✅ Merge successful! febo(https://github.com/febo)'s PR has been merged.
GitHub ↗Provenance
Evidence & technical details
Rollout or chain data, source revisions, freshness and integrity. 2
Provenance
Evidence & technical details
Rollout or chain data, source revisions, freshness and integrity.SIMD
Deployment Status
Feature Gate not yet created
Exact source revision
Sources & integrity
- Proposal document pinned_commit_blob
2934dbeb1c8a7dfecc4f70a93a6b152e525b1698 - simd-document document · stale · Oct 28, 2026
2934dbeb1c8a7dfecc4f70a93a6b152e525b1698
One or more sources are unavailable.
simd.watch community discussion · SIMD-0670
Powered by Giscus · Sign in with GitHub to comment
Community comments load when this section approaches the viewport.