perf(simd186): memoize accounts to avoid double-clone in loadAndValidateTxAccts #187
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Background: SIMD-186 and Account Loading
SIMD-186 changed how account data size limits are validated during transaction loading. When active, Mithril uses
loadAndValidateTxAcctsSimd186()instead of the legacyloadAndValidateTxAccts()function.The key difference: SIMD-186 requires pre-calculating total loaded account sizes (including program data accounts) before building the transaction accounts, to enforce the new size limits correctly.
Problem: Double-Cloning of Accounts
In
pkg/replay/accounts.go, theloadAndValidateTxAcctsSimd186function (lines 210-322) processes accounts in two passes:Pass 1: Size Accumulation (lines 226-236)
Pass 2: Build TransactionAccounts (lines 261-279)
Each
slotCtx.GetAccount()call clones the account:Account.Clone()allocatesmake([]byte, len(Data))Additional O(n) Lookup Issue
The original code also used:
This is O(n) per account in the transaction. For a tx with 10 accounts and 3 instructions, this performs up to 30 comparisons per tx just for program index checks.
Solution: Slice-Based Memoization
1. Cache accounts during Pass 1
2. Replace O(n) slice scan with O(1) boolean mask
3. Reuse cached accounts in Pass 2
4. Reuse cache in program validation
Why Slice Over Map?
map[solana.PublicKey]*Account[]*AccountsliceKey insight:
tx.Message.AccountKeysandtx.AccountMetaList()use identical index ordering. The nth key inAccountKeyscorresponds to the nth entry inAccountMetaList(). This makes positional indexing both correct and optimal.Performance Impact
GetAccountcalls per txConcrete example:
For accounts with large data (programs, token accounts with extensions), this significantly reduces GC pressure.
Edge Cases Preserved
SysvarInstructionsinstrsAcctdirectly (special sysvar)OwnerProgramIDIndexGetAccount(shouldn't occur in valid replay)GetAccount+GetAccountFromAccountsDbFiles Changed
pkg/replay/accounts.goacctCacheslice,isProgramIdxmask, reuse in Pass 2 and validationVerification
go build ./pkg/replay/go test ./pkg/replay/...alloc MB/sandΔgcin 100-slot summary — should decrease🤖 Generated with Claude Code