Skip to content

svm: AccountLoader::load_account() refactor#4680

Merged
2501babe merged 9 commits intoanza-xyz:masterfrom
2501babe:20250129_loadermut
May 8, 2025
Merged

svm: AccountLoader::load_account() refactor#4680
2501babe merged 9 commits intoanza-xyz:masterfrom
2501babe:20250129_loadermut

Conversation

@2501babe
Copy link
Member

@2501babe 2501babe commented Jan 29, 2025

Problem

the program cache refactor (#6036) requires AccountLoader for loading program accounts in functions that are shared with runtime . the cleanest way to do this is to impl TransactionProcessingCallback for AccountLoader

the trick is that AccountLoader updates its internal store with a mut ref, but TXPCB requires an immut ref previously in this pr we attempted to do this by adding interior mutability in AccountLoader, but this was deemed undesirable

also, it is a bit cumbersome for load_account() to accept a bool everywhere. usually we pass in false and it has no effect, but a true in the wrong place could cause bankhash to break. and finally it is annoying that we inspect accounts everywhere we use AccountLoader when really this only needs to be done once per transaction

Summary of Changes

the elegant solution to all these is to cleanly divide up the kinds of loading possible:

  • pub fn load_transaction_account(&mut self, ...): a renamed version of the existing load_account(), which loads from accounts-db or our store, adds to our store if it came from accounts-db, inspects on behalf of bank, and wraps in a LoadedTransactionAccount
  • pub fn load_account(&mut self, ...): a new function that loads and stores but does not inspect or wrap
  • pub fn get_account_shared_data(&self, ...): the TXPCB trait function, which loads and does not store, inspect, or wrap
  • fn do_load(&self, ...): a private helper used by all three, so that the load match is not copy-pasted anywhere, because it is crucial that it behaves predictably across all variant interfaces

despite the added complexity, this is mostly foolproof. as long as you use load_transaction_account() for transaction loading (inspecting any writable accounts before they are written to) it really doesnt matter which function you use anywhere else, they all have the same correctness

also im renaming account_cache to loaded_accounts. this was a very ill-chosen name. the intermediate AccountLoader store a) does not evict, and b) never becomes stale. so its not technically a cache, its just a memoization layer

@2501babe 2501babe self-assigned this Jan 29, 2025
@2501babe 2501babe force-pushed the 20250129_loadermut branch from 3f13c1e to 353df24 Compare March 19, 2025 09:11
@2501babe 2501babe marked this pull request as ready for review March 19, 2025 11:21
@2501babe 2501babe requested a review from a team as a code owner March 19, 2025 11:21
@2501babe 2501babe requested a review from apfitzge March 19, 2025 11:21
@2501babe 2501babe force-pushed the 20250129_loadermut branch from 353df24 to f9c972a Compare March 19, 2025 19:40
@2501babe 2501babe marked this pull request as draft March 19, 2025 19:44
@2501babe 2501babe force-pushed the 20250129_loadermut branch from f9c972a to 65ff38b Compare March 20, 2025 05:09
@2501babe 2501babe marked this pull request as ready for review March 20, 2025 13:34
@2501babe 2501babe marked this pull request as draft March 20, 2025 16:01
@2501babe 2501babe force-pushed the 20250129_loadermut branch from 2473c41 to 556f843 Compare April 19, 2025 14:12
@2501babe 2501babe changed the title svm: AccountLoader mutability refactor svm: AccountLoader::load_account() refactor Apr 19, 2025
@2501babe 2501babe force-pushed the 20250129_loadermut branch from 556f843 to e051595 Compare April 19, 2025 15:02
@codecov-commenter
Copy link

codecov-commenter commented Apr 19, 2025

Codecov Report

Attention: Patch coverage is 95.20548% with 7 lines in your changes missing coverage. Please review.

Project coverage is 82.9%. Comparing base (cf6946d) to head (28483e0).
Report is 3 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff            @@
##           master    #4680    +/-   ##
========================================
  Coverage    82.8%    82.9%            
========================================
  Files         842      842            
  Lines      377455   377560   +105     
========================================
+ Hits       312895   313044   +149     
+ Misses      64560    64516    -44     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@2501babe 2501babe marked this pull request as ready for review April 20, 2025 13:32
@2501babe 2501babe requested a review from apfitzge April 20, 2025 13:33
@2501babe
Copy link
Member Author

note i resolved the previous comment thread because it is no longer relevant, we do not change AccountLoader to use interior mutability anymore. in fact the entire pr has more or less been rewritten, so history is not important and best to think of it as brand new

@2501babe 2501babe force-pushed the 20250129_loadermut branch from 14ed2d8 to eb6c4f3 Compare April 23, 2025 12:29
@2501babe 2501babe requested a review from apfitzge April 28, 2025 09:26
@2501babe 2501babe force-pushed the 20250129_loadermut branch 2 times, most recently from b739b59 to 5cdd772 Compare April 30, 2025 07:12
@2501babe 2501babe force-pushed the 20250129_loadermut branch from 5cdd772 to 28483e0 Compare May 6, 2025 15:04
Copy link

@apfitzge apfitzge left a comment

Choose a reason for hiding this comment

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

LGTM

@2501babe
Copy link
Member Author

2501babe commented May 6, 2025

@anza-xyz/svm this is now ready for review

..
}) = account_loader.load_account(program_id, false)
else {
let Some(program_account) = account_loader.load_account(program_id) else {
Copy link

Choose a reason for hiding this comment

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

Shouldn't this one and the usage below maintain the old behavior (checking the account)?

Copy link
Member Author

@2501babe 2501babe May 7, 2025

Choose a reason for hiding this comment

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

the program_id load has already been inspected at this point, when all the account keys for the transaction were loaded. in fact we could just as easily get the account off the accounts vec by index, it just makes the code look a bit nicer to get it from AccountLoader again. the owner_id load below, the transaction isnt using the account for anything, we just want to check the owner of the owner of the program

i dont think anyone has defined anywhere exactly what "inspection" means from the point of view of svm (the caller of the trait), but this is what me and @brooksprumo have arrived at after many discussions. but "inspection" from the point of view of bank (the main implementor of the trait) is very clear though: the first writable inspection must come before the account is modified. future writable inspects are meaningless. all read-only inspects are noops

Choose a reason for hiding this comment

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

Yep. For the accounts lattice hash, we need to know the initial state (version) of each account modified in a slot. So that means (1) we don't care about accounts loaded read-only, and (2) we only care about the first time an account is modified in the slot. The Bank will implicitly have the final state (version) available.

@2501babe 2501babe merged commit cce41f9 into anza-xyz:master May 8, 2025
47 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants