@@ -105,7 +105,7 @@ static const fd_cluster_version_t FD_RUNTIME_CLUSTER_VERSION = {
105105/* The bpf loader's serialization footprint is bounded in the worst case
106106 by 64 unique writable accounts which are each 10MiB in size (bounded
107107 by the amount of transaction accounts). We can also have up to
108- FD_INSTR_ACCT_MAX (256 ) referenced accounts in an instruction.
108+ FD_BPF_INSTR_ACCT_MAX (255 ) referenced accounts in an instruction.
109109
110110 - 8 bytes for the account count
111111 For each account:
@@ -147,8 +147,63 @@ static const fd_cluster_version_t FD_RUNTIME_CLUSTER_VERSION = {
147147#define FD_ACCOUNT_REC_ALIGN (8UL)
148148/* https://github.com/anza-xyz/sbpf/blob/v0.12.2/src/ebpf.rs#L37-L38 */
149149#define FD_RUNTIME_EBPF_HOST_ALIGN (16UL)
150- #define FD_INSTR_ACCT_MAX (256)
151150
151+ /* FD_INSTR_ACCT_MAX is the maximum number of accounts that can
152+ be referenced by a single instruction.
153+
154+ This is different from FD_BPF_INSTR_ACCT_MAX, which is enforced by the
155+ BPF serializer. It is possible to pass in more than FD_BPF_INSTR_ACCT_MAX
156+ instruction accounts in a transaction (for example mainnet transaction)
157+ 3eDdfZE6HswPxFKrtnQPsEmTkyL1iP57gRPEXwaqNGAqF1paGXCYYMwh7z4uQDUMgFor742sikVSQZW1gFRDhPNh).
158+
159+ A transaction like this will be loaded and sanitized, but will fail in the
160+ bpf serialization stage. It is also possible to invoke a native program with
161+ more than FD_BPF_INSTR_ACCT_MAX instruction accounts that will execute successfully.
162+
163+ Therefore we need to derive a bound from a worst-case transaction: one that
164+ has the maximum possible number of instruction accounts at the expense of
165+ everything else. This is a legacy transaction with a single account address,
166+ a single signature, a single instruction with empty data and as many
167+ instruction accounts as possible.
168+
169+ Therefore, the maximum number of instruction accounts is:
170+ (MTU - fixed overhead) / (size of instruction account)
171+ = (MTU
172+ - signature count (1 byte, value=1)
173+ - signature (64 bytes)
174+ - signature count in header (1 byte)
175+ - readonly signed count (1 byte)
176+ - readonly unsigned count (1 byte)
177+ - account count (1 byte, compact-u16 value=1)
178+ - 1 account address (32 bytes)
179+ - recent blockhash (32 bytes)
180+ - instruction count (1 byte, compact-u16 value=1)
181+ - program id index (1 byte)
182+ - instruction account count (2 bytes)
183+ - data len (1 byte, value=0)
184+ = 1232 - 1 - 64 - 1 - 1 - 1 - 1 - 32 - 32 - 1 - 1 - 2 - 1
185+ = 1094
186+
187+ TODO: SIMD-406 (https://github.com/solana-foundation/solana-improvement-documents/pull/406)
188+ limits the number of instruction accounts to 255 in transaction sanitization.
189+
190+ Once the corresponding feature gate has been activated, we can reduce
191+ FD_INSTR_ACCT_MAX to 255. We cannot reduce this before as this would cause
192+ the result of the get_processed_sibling_instruction syscall to diverge from
193+ Agave. */
194+ #define FD_INSTR_ACCT_MAX (1060UL)
195+
196+ /* FD_BPF_INSTR_ACCT_MAX is the maximum number of accounts that
197+ an instruction that goes through the bpf loader serializer can reference.
198+
199+ The BPF loader has a lower limit for the number of instruction accounts
200+ than is enforced in transaction sanitization.
201+
202+ TODO: remove this limit once SIMD-406 is activated, as we can then use the
203+ same limit everywhere.
204+
205+ https://github.com/anza-xyz/agave/blob/v3.1.4/transaction-context/src/lib.rs#L30-L32 */
206+ #define FD_BPF_INSTR_ACCT_MAX (255UL)
152207
153208#define FD_BPF_LOADER_UNIQUE_ACCOUNT_FOOTPRINT (direct_mapping ) \
154209 (1UL /* dup byte */ + \
@@ -168,7 +223,7 @@ static const fd_cluster_version_t FD_RUNTIME_CLUSTER_VERSION = {
168223#define FD_BPF_LOADER_INPUT_REGION_FOOTPRINT (account_lock_limit , direct_mapping ) \
169224 (FD_ULONG_ALIGN_UP( (sizeof(ulong) /* acct_cnt */ + \
170225 account_lock_limit * FD_BPF_LOADER_UNIQUE_ACCOUNT_FOOTPRINT (direct_mapping ) + \
171- (FD_INSTR_ACCT_MAX - account_lock_limit )* FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT + \
226+ (FD_BPF_INSTR_ACCT_MAX - account_lock_limit )* FD_BPF_LOADER_DUPLICATE_ACCOUNT_FOOTPRINT + \
172227 sizeof (ulong ) /* instr data len */ + \
173228 FD_TXN_MTU /* No instr data */ + \
174229 sizeof (fd_pubkey_t )), /* program id */ \
0 commit comments