Improving ABIv1 invoke syscall
#622
febo
started this conversation in
SIMD Discussions
Replies: 2 comments
|
The proposed solution sounds best to me, the usability of |
0 replies
|
Love it. I've wanted this for years. I personally think using the account index idea is a much better approach. It can be statically allocated, results in cleaner assembly, consumes fewer CUs, and disincentivizes the anti-pattern of having variable accounts. Users will already be using indexes to pull the |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Motivation
Currently, configuring CPI parameters in ABIv1 programs is unnecessarily cumbersome:
&[AccountMeta]and&[AccountInfo].Both requirements force programs to allocate and copy more memory than strictly necessary. This overhead could be avoided without negatively affecting runtime performance. An
AccountMetaoccupies34bytes, while anAccountInfooccupies56bytes. Therefore, a program must manipulate90bytes per account for each CPI. This often requires heap allocation because the total size can exceed the maximum stack size of4096bytes, particularly given that a CPI can accept up to255accounts.Proposed Solution
To address the first issue, we can eliminate one of the account slices by combining the information contained in
AccountMetaandAccountInfo. The purpose ofAccountMetais to associate the writable and signer flags with an account, whileAccountInfocontains the actual account information.The second issue can be mitigated by allowing programs to simply pass a pointer to the account rather than requiring them to copy the account information into a different layout.
These two changes can be combined by defining a type that associates an account pointer with the writable/signer flags:
The program can then create a new
CpiInstructioncontaining a single slice of the accounts expected by the invoked program:Finally, the
CpiInstructionis used as a parameter to a new invoke syscall:By using a
CpiAccountto represent accounts, the memory requirement is reduced from90to16bytes per account, including6bytes of padding. The program itself copies only10bytes per account.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 account pointer during account translation.
Alternatives Considered
We investigated two other alternatives for simplifying CPI setup in programs. Here we present them and discuss their drawbacks.
A) Use a slice of account pointers
Account information received by an entrypoint is represented by a RuntimeAccount, which is wrapped in an AccountView, and programs written with Pinocchio receive a slice of
AccountViews at their entrypoint. Rather than allocating and copying56bytes for eachAccountInfo, a program could pass a slice ofAccountViews, requiring only8bytes per account. This would reduce the per-account memory requirement for a CPI from90bytes to42bytes (34+8bytes).The new
invokev2 syscall would then expectaccounts_addrandaccounts_lento describe a slice ofAccountViews:However, this alternative does not address one of the issues described above: programs would still need to pass two account slices.
B) Use account indices instead of pointers
Another alternative is to use each account’s index in the instruction rather than a reference to the account. This would reduce the memory requirement to
4bytes per account. To support this approach, theCpiAccountdefinition would use the account index and the writable and signer flags. The definitions ofCpiInstructionandsol_invoke_signed_v2would remain the same as in the proposed solution.In addition to reducing memory usage, this approach allows the CPI account list to be constructed statically at compile time when the program’s account list is deterministic. Otherwise, the program can construct it dynamically.
However, this approach would make it more difficult for helper functions to ensure that an account is not currently borrowed before a CPI. The index is not stored in an
AccountView, and mapping an index to the correspondingAccountViewis not straightforward. To preserve the current behavior, helper functions would need to accept both the account index and a reference to the account.Another consideration is that, although this approach resembles ABIv2, it could cause confusion during migration because ABIv2 expects transaction account indices, while this alternative uses instruction account indices.
Benchmark
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. The purpose is to show the improvements during the setup of CPI parameters. All others costs of a CPI remain the same.
*In addition to reducing CU consumption, this change simplifies the API that programs use to perform CPIs.
All reactions