Skip to content

Commit 4577c4b

Browse files
author
HaoranYi
committed
reorder load_account and program_cache replenish
1 parent d6102b4 commit 4577c4b

File tree

5 files changed

+440
-546
lines changed

5 files changed

+440
-546
lines changed

runtime/src/bank.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6737,7 +6737,6 @@ impl Bank {
67376737
effective_epoch,
67386738
self.epoch_schedule(),
67396739
reload,
6740-
&HashMap::default(),
67416740
)
67426741
}
67436742

svm/src/account_loader.rs

Lines changed: 74 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use {
3232
transaction_context::{IndexOfAccount, TransactionAccount},
3333
},
3434
solana_system_program::{get_system_account_kind, SystemAccountKind},
35+
std::collections::hash_map::Entry,
3536
std::{collections::HashMap, num::NonZeroUsize},
3637
};
3738

@@ -108,15 +109,16 @@ pub fn validate_fee_payer(
108109
/// batch. Each tuple contains struct of information about accounts as
109110
/// its first element and an optional transaction nonce info as its
110111
/// second element.
112+
/// This function also populate program_accounts map.
111113
pub(crate) fn load_accounts<CB: TransactionProcessingCallback>(
112114
callbacks: &CB,
113115
txs: &[SanitizedTransaction],
114116
check_results: &[TransactionCheckResult],
115117
error_counters: &mut TransactionErrorMetrics,
116118
fee_structure: &FeeStructure,
117119
account_overrides: Option<&AccountOverrides>,
118-
loaded_programs: &ProgramCacheForTxBatch,
119-
accounts_map: &HashMap<Pubkey, Option<(AccountSharedData, Slot)>>,
120+
program_owners: &[Pubkey],
121+
program_accounts: &mut HashMap<Pubkey, u64>,
120122
) -> Vec<TransactionLoadResult> {
121123
let feature_set = callbacks.get_feature_set();
122124
txs.iter()
@@ -146,8 +148,8 @@ pub(crate) fn load_accounts<CB: TransactionProcessingCallback>(
146148
fee,
147149
error_counters,
148150
account_overrides,
149-
loaded_programs,
150-
accounts_map,
151+
program_owners,
152+
program_accounts,
151153
) {
152154
Ok(loaded_transaction) => loaded_transaction,
153155
Err(e) => return (Err(e), None),
@@ -183,20 +185,11 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
183185
fee: u64,
184186
error_counters: &mut TransactionErrorMetrics,
185187
account_overrides: Option<&AccountOverrides>,
186-
loaded_programs: &ProgramCacheForTxBatch,
187-
accounts_map: &HashMap<Pubkey, Option<(AccountSharedData, Slot)>>,
188+
program_owners: &[Pubkey],
189+
program_accounts: &mut HashMap<Pubkey, u64>,
188190
) -> Result<LoadedTransaction> {
189191
let feature_set = callbacks.get_feature_set();
190192

191-
let load_account = |pubkey, should_cache| {
192-
let maybe_found = if let Some(found) = accounts_map.get(pubkey) {
193-
found.as_ref().cloned()
194-
} else {
195-
callbacks.load_account_with(pubkey, |_| should_cache)
196-
};
197-
maybe_found.map(|x| x.0)
198-
};
199-
200193
// There is no way to predict what program will execute without an error
201194
// If a fee can pay for execution then the program will be scheduled
202195
let mut validated_fee_payer = false;
@@ -210,13 +203,6 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
210203
get_requested_loaded_accounts_data_size_limit(message)?;
211204
let mut accumulated_accounts_data_size: usize = 0;
212205

213-
let instruction_accounts = message
214-
.instructions()
215-
.iter()
216-
.flat_map(|instruction| &instruction.accounts)
217-
.unique()
218-
.collect::<Vec<&u8>>();
219-
220206
let mut accounts = account_keys
221207
.iter()
222208
.enumerate()
@@ -226,26 +212,30 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
226212
let account = if solana_sdk::sysvar::instructions::check_id(key) {
227213
construct_instructions_account(message)
228214
} else {
229-
let instruction_account = u8::try_from(i)
230-
.map(|i| instruction_accounts.contains(&&i))
231-
.unwrap_or(false);
232215
let (account_size, mut account, rent) = if let Some(account_override) =
233216
account_overrides.and_then(|overrides| overrides.get(key))
234217
{
235218
(account_override.data().len(), account_override.clone(), 0)
236-
} else if let Some(program) = (!instruction_account && !message.is_writable(i))
237-
.then_some(())
238-
.and_then(|_| loaded_programs.find(key))
239-
{
240-
load_account(key, false).ok_or(TransactionError::AccountNotFound)?;
241-
// Optimization to skip loading of accounts which are only used as
242-
// programs in top-level instructions and not passed as instruction accounts.
243-
let program_account = account_shared_data_from_program(&program);
244-
(program.account_size, program_account, 0)
245219
} else {
246-
load_account(key, !message.is_writable(i))
247-
.map(|mut account| {
248-
if message.is_writable(i) {
220+
let is_account_writable = message.is_writable(i);
221+
callbacks
222+
.load_account_with(key, |account| {
223+
// only cache account that is not writable and not having program owners.
224+
!is_account_writable && !program_owners.contains(account.owner())
225+
})
226+
.map(|(mut account, _slot)| {
227+
if program_owners.contains(account.owner()) {
228+
match program_accounts.entry(*key) {
229+
Entry::Vacant(entry) => {
230+
entry.insert(1);
231+
}
232+
Entry::Occupied(mut entry) => {
233+
let count = entry.get_mut();
234+
saturating_add_assign!(*count, 1);
235+
}
236+
}
237+
}
238+
if is_account_writable {
249239
if !feature_set
250240
.is_active(&feature_set::disable_rent_fees_collection::id())
251241
{
@@ -563,15 +553,16 @@ mod tests {
563553
rent_collector: rent_collector.clone(),
564554
feature_set: Arc::new(feature_set.clone()),
565555
};
556+
let mut program_accounts = HashMap::default();
566557
load_accounts(
567558
&callbacks,
568559
&[sanitized_tx],
569560
&[(Ok(()), None, Some(lamports_per_signature))],
570561
error_counters,
571562
fee_structure,
572563
None,
573-
&ProgramCacheForTxBatch::default(),
574-
&HashMap::default(),
564+
&[],
565+
&mut program_accounts,
575566
)
576567
}
577568

@@ -1052,15 +1043,17 @@ mod tests {
10521043
rent_collector: RentCollector::default(),
10531044
feature_set: Arc::new(FeatureSet::all_enabled()),
10541045
};
1046+
1047+
let mut program_accounts = HashMap::default();
10551048
load_accounts(
10561049
&callbacks,
10571050
&[tx],
10581051
&[(Ok(()), None, Some(10))],
10591052
&mut error_counters,
10601053
&FeeStructure::default(),
10611054
account_overrides,
1062-
&ProgramCacheForTxBatch::default(),
1063-
&HashMap::default(),
1055+
&[],
1056+
&mut program_accounts,
10641057
)
10651058
}
10661059

@@ -1451,21 +1444,21 @@ mod tests {
14511444
let sanitized_message = new_unchecked_sanitized_message(message);
14521445
let mock_bank = TestCallbacks::default();
14531446
let mut error_counter = TransactionErrorMetrics::default();
1454-
let loaded_programs = ProgramCacheForTxBatch::default();
14551447

14561448
let sanitized_transaction = SanitizedTransaction::new_for_tests(
14571449
sanitized_message,
14581450
vec![Signature::new_unique()],
14591451
false,
14601452
);
1453+
14611454
let result = load_transaction_accounts(
14621455
&mock_bank,
14631456
sanitized_transaction.message(),
14641457
32,
14651458
&mut error_counter,
14661459
None,
1467-
&loaded_programs,
1468-
&HashMap::default(),
1460+
&[],
1461+
&mut HashMap::default(),
14691462
);
14701463

14711464
assert_eq!(result.err(), Some(TransactionError::AccountNotFound));
@@ -1508,8 +1501,8 @@ mod tests {
15081501
32,
15091502
&mut error_counter,
15101503
None,
1511-
&loaded_programs,
1512-
&HashMap::default(),
1504+
&[],
1505+
&mut HashMap::default(),
15131506
);
15141507
mock_bank
15151508
.accounts_map
@@ -1560,8 +1553,8 @@ mod tests {
15601553
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
15611554

15621555
let mut error_counter = TransactionErrorMetrics::default();
1563-
let mut loaded_programs = ProgramCacheForTxBatch::default();
1564-
loaded_programs.replenish(key2.pubkey(), Arc::new(ProgramCacheEntry::default()));
1556+
// let mut loaded_programs = ProgramCacheForTxBatch::default();
1557+
// loaded_programs.replenish(key2.pubkey(), Arc::new(ProgramCacheEntry::default()));
15651558

15661559
let sanitized_transaction = SanitizedTransaction::new_for_tests(
15671560
sanitized_message,
@@ -1574,11 +1567,17 @@ mod tests {
15741567
32,
15751568
&mut error_counter,
15761569
None,
1577-
&loaded_programs,
1578-
&HashMap::default(),
1570+
&[],
1571+
&mut HashMap::default(),
15791572
);
15801573

1581-
assert_eq!(result.err(), Some(TransactionError::AccountNotFound));
1574+
// The original code throws "AccountNotFound" error. With this PR, it
1575+
// throws "ProgramAccountNotFound" error. But I don't think this is a
1576+
// concern for breaking consensus. As the original "AccountNotFound"
1577+
// error should not be triggered in real world. When we can find "key"
1578+
// in program_cache, which is after replenish, then it must be in
1579+
// accounts-db.
1580+
assert_eq!(result.err(), Some(TransactionError::ProgramAccountNotFound));
15821581
}
15831582

15841583
#[test]
@@ -1604,7 +1603,6 @@ mod tests {
16041603
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
16051604

16061605
let mut error_counter = TransactionErrorMetrics::default();
1607-
let loaded_programs = ProgramCacheForTxBatch::default();
16081606

16091607
let sanitized_transaction = SanitizedTransaction::new_for_tests(
16101608
sanitized_message,
@@ -1617,8 +1615,8 @@ mod tests {
16171615
32,
16181616
&mut error_counter,
16191617
None,
1620-
&loaded_programs,
1621-
&HashMap::default(),
1618+
&[],
1619+
&mut HashMap::default(),
16221620
);
16231621

16241622
assert_eq!(result.err(), Some(TransactionError::ProgramAccountNotFound));
@@ -1647,7 +1645,6 @@ mod tests {
16471645
mock_bank.accounts_map.insert(key1.pubkey(), account_data);
16481646

16491647
let mut error_counter = TransactionErrorMetrics::default();
1650-
let loaded_programs = ProgramCacheForTxBatch::default();
16511648

16521649
let sanitized_transaction = SanitizedTransaction::new_for_tests(
16531650
sanitized_message,
@@ -1660,8 +1657,8 @@ mod tests {
16601657
32,
16611658
&mut error_counter,
16621659
None,
1663-
&loaded_programs,
1664-
&HashMap::default(),
1660+
&[],
1661+
&mut HashMap::default(),
16651662
);
16661663

16671664
assert_eq!(
@@ -1697,7 +1694,6 @@ mod tests {
16971694
account_data.set_lamports(200);
16981695
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
16991696
let mut error_counter = TransactionErrorMetrics::default();
1700-
let loaded_programs = ProgramCacheForTxBatch::default();
17011697

17021698
let sanitized_transaction = SanitizedTransaction::new_for_tests(
17031699
sanitized_message,
@@ -1710,8 +1706,8 @@ mod tests {
17101706
32,
17111707
&mut error_counter,
17121708
None,
1713-
&loaded_programs,
1714-
&HashMap::default(),
1709+
&[],
1710+
&mut HashMap::default(),
17151711
);
17161712
mock_bank
17171713
.accounts_map
@@ -1765,7 +1761,6 @@ mod tests {
17651761
account_data.set_lamports(200);
17661762
mock_bank.accounts_map.insert(key2.pubkey(), account_data);
17671763
let mut error_counter = TransactionErrorMetrics::default();
1768-
let loaded_programs = ProgramCacheForTxBatch::default();
17691764

17701765
let sanitized_transaction = SanitizedTransaction::new_for_tests(
17711766
sanitized_message,
@@ -1778,8 +1773,8 @@ mod tests {
17781773
32,
17791774
&mut error_counter,
17801775
None,
1781-
&loaded_programs,
1782-
&HashMap::default(),
1776+
&[],
1777+
&mut HashMap::default(),
17831778
);
17841779
mock_bank
17851780
.accounts_map
@@ -1835,8 +1830,8 @@ mod tests {
18351830
32,
18361831
&mut error_counter,
18371832
None,
1838-
&loaded_programs,
1839-
&HashMap::default(),
1833+
&[],
1834+
&mut HashMap::default(),
18401835
);
18411836
mock_bank
18421837
.accounts_map
@@ -1897,8 +1892,8 @@ mod tests {
18971892
32,
18981893
&mut error_counter,
18991894
None,
1900-
&loaded_programs,
1901-
&HashMap::default(),
1895+
&[],
1896+
&mut HashMap::default(),
19021897
);
19031898
mock_bank
19041899
.accounts_map
@@ -1985,8 +1980,8 @@ mod tests {
19851980
32,
19861981
&mut error_counter,
19871982
None,
1988-
&loaded_programs,
1989-
&HashMap::default(),
1983+
&[],
1984+
&mut HashMap::default(),
19901985
);
19911986
mock_bank
19921987
.accounts_map
@@ -2057,8 +2052,8 @@ mod tests {
20572052
&mut error_counters,
20582053
&FeeStructure::default(),
20592054
None,
2060-
&ProgramCacheForTxBatch::default(),
2061-
&HashMap::default(),
2055+
&[],
2056+
&mut HashMap::default(),
20622057
);
20632058

20642059
let compute_budget = ComputeBudget::new(u64::from(
@@ -2141,8 +2136,8 @@ mod tests {
21412136
&mut error_counter,
21422137
&FeeStructure::default(),
21432138
None,
2144-
&loaded_programs,
2145-
&HashMap::default(),
2139+
&[],
2140+
&mut HashMap::default(),
21462141
);
21472142

21482143
let mut account_data = AccountSharedData::default();
@@ -2215,8 +2210,8 @@ mod tests {
22152210
&mut TransactionErrorMetrics::default(),
22162211
&fee_structure,
22172212
None,
2218-
&ProgramCacheForTxBatch::default(),
2219-
&HashMap::default(),
2213+
&[],
2214+
&mut HashMap::default(),
22202215
);
22212216

22222217
assert_eq!(
@@ -2234,8 +2229,8 @@ mod tests {
22342229
&mut TransactionErrorMetrics::default(),
22352230
&fee_structure,
22362231
None,
2237-
&ProgramCacheForTxBatch::default(),
2238-
&HashMap::default(),
2232+
&[],
2233+
&mut HashMap::default(),
22392234
);
22402235

22412236
assert_eq!(result, vec![(Err(TransactionError::AccountNotFound), None)]);
@@ -2253,8 +2248,8 @@ mod tests {
22532248
&mut TransactionErrorMetrics::default(),
22542249
&fee_structure,
22552250
None,
2256-
&ProgramCacheForTxBatch::default(),
2257-
&HashMap::default(),
2251+
&[],
2252+
&mut HashMap::default(),
22582253
);
22592254

22602255
assert_eq!(

0 commit comments

Comments
 (0)