svm: AccountLoader::load_account() refactor#4680
Conversation
18ebd77 to
3f13c1e
Compare
3f13c1e to
353df24
Compare
353df24 to
f9c972a
Compare
f9c972a to
65ff38b
Compare
2473c41 to
556f843
Compare
AccountLoader mutability refactorAccountLoader::load_account() refactor
556f843 to
e051595
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files🚀 New features to boost your workflow:
|
|
note i resolved the previous comment thread because it is no longer relevant, we do not change |
14ed2d8 to
eb6c4f3
Compare
b739b59 to
5cdd772
Compare
5cdd772 to
28483e0
Compare
|
@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 { |
There was a problem hiding this comment.
Shouldn't this one and the usage below maintain the old behavior (checking the account)?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
Problem
the program cache refactor (#6036) requires
AccountLoaderfor loading program accounts in functions that are shared withruntime. the cleanest way to do this is toimpl TransactionProcessingCallback for AccountLoaderthe trick is that
AccountLoaderupdates 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 inAccountLoader, but this was deemed undesirablealso, it is a bit cumbersome for
load_account()to accept a bool everywhere. usually we pass infalseand it has no effect, but atruein the wrong place could cause bankhash to break. and finally it is annoying that we inspect accounts everywhere we useAccountLoaderwhen really this only needs to be done once per transactionSummary 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 existingload_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 aLoadedTransactionAccountpub fn load_account(&mut self, ...): a new function that loads and stores but does not inspect or wrappub fn get_account_shared_data(&self, ...): the TXPCB trait function, which loads and does not store, inspect, or wrapfn do_load(&self, ...): a private helper used by all three, so that the loadmatchis not copy-pasted anywhere, because it is crucial that it behaves predictably across all variant interfacesdespite 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 correctnessalso im renaming
account_cachetoloaded_accounts. this was a very ill-chosen name. the intermediateAccountLoaderstore a) does not evict, and b) never becomes stale. so its not technically a cache, its just a memoization layer