32
32
transaction_context:: { IndexOfAccount , TransactionAccount } ,
33
33
} ,
34
34
solana_system_program:: { get_system_account_kind, SystemAccountKind } ,
35
+ std:: collections:: hash_map:: Entry ,
35
36
std:: { collections:: HashMap , num:: NonZeroUsize } ,
36
37
} ;
37
38
@@ -108,15 +109,16 @@ pub fn validate_fee_payer(
108
109
/// batch. Each tuple contains struct of information about accounts as
109
110
/// its first element and an optional transaction nonce info as its
110
111
/// second element.
112
+ /// This function also populate program_accounts map.
111
113
pub ( crate ) fn load_accounts < CB : TransactionProcessingCallback > (
112
114
callbacks : & CB ,
113
115
txs : & [ SanitizedTransaction ] ,
114
116
check_results : & [ TransactionCheckResult ] ,
115
117
error_counters : & mut TransactionErrorMetrics ,
116
118
fee_structure : & FeeStructure ,
117
119
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 > ,
120
122
) -> Vec < TransactionLoadResult > {
121
123
let feature_set = callbacks. get_feature_set ( ) ;
122
124
txs. iter ( )
@@ -146,8 +148,8 @@ pub(crate) fn load_accounts<CB: TransactionProcessingCallback>(
146
148
fee,
147
149
error_counters,
148
150
account_overrides,
149
- loaded_programs ,
150
- accounts_map ,
151
+ program_owners ,
152
+ program_accounts ,
151
153
) {
152
154
Ok ( loaded_transaction) => loaded_transaction,
153
155
Err ( e) => return ( Err ( e) , None ) ,
@@ -183,20 +185,11 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
183
185
fee : u64 ,
184
186
error_counters : & mut TransactionErrorMetrics ,
185
187
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 > ,
188
190
) -> Result < LoadedTransaction > {
189
191
let feature_set = callbacks. get_feature_set ( ) ;
190
192
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
-
200
193
// There is no way to predict what program will execute without an error
201
194
// If a fee can pay for execution then the program will be scheduled
202
195
let mut validated_fee_payer = false ;
@@ -210,13 +203,6 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
210
203
get_requested_loaded_accounts_data_size_limit ( message) ?;
211
204
let mut accumulated_accounts_data_size: usize = 0 ;
212
205
213
- let instruction_accounts = message
214
- . instructions ( )
215
- . iter ( )
216
- . flat_map ( |instruction| & instruction. accounts )
217
- . unique ( )
218
- . collect :: < Vec < & u8 > > ( ) ;
219
-
220
206
let mut accounts = account_keys
221
207
. iter ( )
222
208
. enumerate ( )
@@ -226,26 +212,30 @@ fn load_transaction_accounts<CB: TransactionProcessingCallback>(
226
212
let account = if solana_sdk:: sysvar:: instructions:: check_id ( key) {
227
213
construct_instructions_account ( message)
228
214
} else {
229
- let instruction_account = u8:: try_from ( i)
230
- . map ( |i| instruction_accounts. contains ( & & i) )
231
- . unwrap_or ( false ) ;
232
215
let ( account_size, mut account, rent) = if let Some ( account_override) =
233
216
account_overrides. and_then ( |overrides| overrides. get ( key) )
234
217
{
235
218
( 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 )
245
219
} 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 {
249
239
if !feature_set
250
240
. is_active ( & feature_set:: disable_rent_fees_collection:: id ( ) )
251
241
{
@@ -563,15 +553,16 @@ mod tests {
563
553
rent_collector : rent_collector. clone ( ) ,
564
554
feature_set : Arc :: new ( feature_set. clone ( ) ) ,
565
555
} ;
556
+ let mut program_accounts = HashMap :: default ( ) ;
566
557
load_accounts (
567
558
& callbacks,
568
559
& [ sanitized_tx] ,
569
560
& [ ( Ok ( ( ) ) , None , Some ( lamports_per_signature) ) ] ,
570
561
error_counters,
571
562
fee_structure,
572
563
None ,
573
- & ProgramCacheForTxBatch :: default ( ) ,
574
- & HashMap :: default ( ) ,
564
+ & [ ] ,
565
+ & mut program_accounts ,
575
566
)
576
567
}
577
568
@@ -1052,15 +1043,17 @@ mod tests {
1052
1043
rent_collector : RentCollector :: default ( ) ,
1053
1044
feature_set : Arc :: new ( FeatureSet :: all_enabled ( ) ) ,
1054
1045
} ;
1046
+
1047
+ let mut program_accounts = HashMap :: default ( ) ;
1055
1048
load_accounts (
1056
1049
& callbacks,
1057
1050
& [ tx] ,
1058
1051
& [ ( Ok ( ( ) ) , None , Some ( 10 ) ) ] ,
1059
1052
& mut error_counters,
1060
1053
& FeeStructure :: default ( ) ,
1061
1054
account_overrides,
1062
- & ProgramCacheForTxBatch :: default ( ) ,
1063
- & HashMap :: default ( ) ,
1055
+ & [ ] ,
1056
+ & mut program_accounts ,
1064
1057
)
1065
1058
}
1066
1059
@@ -1451,21 +1444,21 @@ mod tests {
1451
1444
let sanitized_message = new_unchecked_sanitized_message ( message) ;
1452
1445
let mock_bank = TestCallbacks :: default ( ) ;
1453
1446
let mut error_counter = TransactionErrorMetrics :: default ( ) ;
1454
- let loaded_programs = ProgramCacheForTxBatch :: default ( ) ;
1455
1447
1456
1448
let sanitized_transaction = SanitizedTransaction :: new_for_tests (
1457
1449
sanitized_message,
1458
1450
vec ! [ Signature :: new_unique( ) ] ,
1459
1451
false ,
1460
1452
) ;
1453
+
1461
1454
let result = load_transaction_accounts (
1462
1455
& mock_bank,
1463
1456
sanitized_transaction. message ( ) ,
1464
1457
32 ,
1465
1458
& mut error_counter,
1466
1459
None ,
1467
- & loaded_programs ,
1468
- & HashMap :: default ( ) ,
1460
+ & [ ] ,
1461
+ & mut HashMap :: default ( ) ,
1469
1462
) ;
1470
1463
1471
1464
assert_eq ! ( result. err( ) , Some ( TransactionError :: AccountNotFound ) ) ;
@@ -1508,8 +1501,8 @@ mod tests {
1508
1501
32 ,
1509
1502
& mut error_counter,
1510
1503
None ,
1511
- & loaded_programs ,
1512
- & HashMap :: default ( ) ,
1504
+ & [ ] ,
1505
+ & mut HashMap :: default ( ) ,
1513
1506
) ;
1514
1507
mock_bank
1515
1508
. accounts_map
@@ -1560,8 +1553,8 @@ mod tests {
1560
1553
mock_bank. accounts_map . insert ( key1. pubkey ( ) , account_data) ;
1561
1554
1562
1555
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()));
1565
1558
1566
1559
let sanitized_transaction = SanitizedTransaction :: new_for_tests (
1567
1560
sanitized_message,
@@ -1574,11 +1567,17 @@ mod tests {
1574
1567
32 ,
1575
1568
& mut error_counter,
1576
1569
None ,
1577
- & loaded_programs ,
1578
- & HashMap :: default ( ) ,
1570
+ & [ ] ,
1571
+ & mut HashMap :: default ( ) ,
1579
1572
) ;
1580
1573
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 ) ) ;
1582
1581
}
1583
1582
1584
1583
#[ test]
@@ -1604,7 +1603,6 @@ mod tests {
1604
1603
mock_bank. accounts_map . insert ( key1. pubkey ( ) , account_data) ;
1605
1604
1606
1605
let mut error_counter = TransactionErrorMetrics :: default ( ) ;
1607
- let loaded_programs = ProgramCacheForTxBatch :: default ( ) ;
1608
1606
1609
1607
let sanitized_transaction = SanitizedTransaction :: new_for_tests (
1610
1608
sanitized_message,
@@ -1617,8 +1615,8 @@ mod tests {
1617
1615
32 ,
1618
1616
& mut error_counter,
1619
1617
None ,
1620
- & loaded_programs ,
1621
- & HashMap :: default ( ) ,
1618
+ & [ ] ,
1619
+ & mut HashMap :: default ( ) ,
1622
1620
) ;
1623
1621
1624
1622
assert_eq ! ( result. err( ) , Some ( TransactionError :: ProgramAccountNotFound ) ) ;
@@ -1647,7 +1645,6 @@ mod tests {
1647
1645
mock_bank. accounts_map . insert ( key1. pubkey ( ) , account_data) ;
1648
1646
1649
1647
let mut error_counter = TransactionErrorMetrics :: default ( ) ;
1650
- let loaded_programs = ProgramCacheForTxBatch :: default ( ) ;
1651
1648
1652
1649
let sanitized_transaction = SanitizedTransaction :: new_for_tests (
1653
1650
sanitized_message,
@@ -1660,8 +1657,8 @@ mod tests {
1660
1657
32 ,
1661
1658
& mut error_counter,
1662
1659
None ,
1663
- & loaded_programs ,
1664
- & HashMap :: default ( ) ,
1660
+ & [ ] ,
1661
+ & mut HashMap :: default ( ) ,
1665
1662
) ;
1666
1663
1667
1664
assert_eq ! (
@@ -1697,7 +1694,6 @@ mod tests {
1697
1694
account_data. set_lamports ( 200 ) ;
1698
1695
mock_bank. accounts_map . insert ( key2. pubkey ( ) , account_data) ;
1699
1696
let mut error_counter = TransactionErrorMetrics :: default ( ) ;
1700
- let loaded_programs = ProgramCacheForTxBatch :: default ( ) ;
1701
1697
1702
1698
let sanitized_transaction = SanitizedTransaction :: new_for_tests (
1703
1699
sanitized_message,
@@ -1710,8 +1706,8 @@ mod tests {
1710
1706
32 ,
1711
1707
& mut error_counter,
1712
1708
None ,
1713
- & loaded_programs ,
1714
- & HashMap :: default ( ) ,
1709
+ & [ ] ,
1710
+ & mut HashMap :: default ( ) ,
1715
1711
) ;
1716
1712
mock_bank
1717
1713
. accounts_map
@@ -1765,7 +1761,6 @@ mod tests {
1765
1761
account_data. set_lamports ( 200 ) ;
1766
1762
mock_bank. accounts_map . insert ( key2. pubkey ( ) , account_data) ;
1767
1763
let mut error_counter = TransactionErrorMetrics :: default ( ) ;
1768
- let loaded_programs = ProgramCacheForTxBatch :: default ( ) ;
1769
1764
1770
1765
let sanitized_transaction = SanitizedTransaction :: new_for_tests (
1771
1766
sanitized_message,
@@ -1778,8 +1773,8 @@ mod tests {
1778
1773
32 ,
1779
1774
& mut error_counter,
1780
1775
None ,
1781
- & loaded_programs ,
1782
- & HashMap :: default ( ) ,
1776
+ & [ ] ,
1777
+ & mut HashMap :: default ( ) ,
1783
1778
) ;
1784
1779
mock_bank
1785
1780
. accounts_map
@@ -1835,8 +1830,8 @@ mod tests {
1835
1830
32 ,
1836
1831
& mut error_counter,
1837
1832
None ,
1838
- & loaded_programs ,
1839
- & HashMap :: default ( ) ,
1833
+ & [ ] ,
1834
+ & mut HashMap :: default ( ) ,
1840
1835
) ;
1841
1836
mock_bank
1842
1837
. accounts_map
@@ -1897,8 +1892,8 @@ mod tests {
1897
1892
32 ,
1898
1893
& mut error_counter,
1899
1894
None ,
1900
- & loaded_programs ,
1901
- & HashMap :: default ( ) ,
1895
+ & [ ] ,
1896
+ & mut HashMap :: default ( ) ,
1902
1897
) ;
1903
1898
mock_bank
1904
1899
. accounts_map
@@ -1985,8 +1980,8 @@ mod tests {
1985
1980
32 ,
1986
1981
& mut error_counter,
1987
1982
None ,
1988
- & loaded_programs ,
1989
- & HashMap :: default ( ) ,
1983
+ & [ ] ,
1984
+ & mut HashMap :: default ( ) ,
1990
1985
) ;
1991
1986
mock_bank
1992
1987
. accounts_map
@@ -2057,8 +2052,8 @@ mod tests {
2057
2052
& mut error_counters,
2058
2053
& FeeStructure :: default ( ) ,
2059
2054
None ,
2060
- & ProgramCacheForTxBatch :: default ( ) ,
2061
- & HashMap :: default ( ) ,
2055
+ & [ ] ,
2056
+ & mut HashMap :: default ( ) ,
2062
2057
) ;
2063
2058
2064
2059
let compute_budget = ComputeBudget :: new ( u64:: from (
@@ -2141,8 +2136,8 @@ mod tests {
2141
2136
& mut error_counter,
2142
2137
& FeeStructure :: default ( ) ,
2143
2138
None ,
2144
- & loaded_programs ,
2145
- & HashMap :: default ( ) ,
2139
+ & [ ] ,
2140
+ & mut HashMap :: default ( ) ,
2146
2141
) ;
2147
2142
2148
2143
let mut account_data = AccountSharedData :: default ( ) ;
@@ -2215,8 +2210,8 @@ mod tests {
2215
2210
& mut TransactionErrorMetrics :: default ( ) ,
2216
2211
& fee_structure,
2217
2212
None ,
2218
- & ProgramCacheForTxBatch :: default ( ) ,
2219
- & HashMap :: default ( ) ,
2213
+ & [ ] ,
2214
+ & mut HashMap :: default ( ) ,
2220
2215
) ;
2221
2216
2222
2217
assert_eq ! (
@@ -2234,8 +2229,8 @@ mod tests {
2234
2229
& mut TransactionErrorMetrics :: default ( ) ,
2235
2230
& fee_structure,
2236
2231
None ,
2237
- & ProgramCacheForTxBatch :: default ( ) ,
2238
- & HashMap :: default ( ) ,
2232
+ & [ ] ,
2233
+ & mut HashMap :: default ( ) ,
2239
2234
) ;
2240
2235
2241
2236
assert_eq ! ( result, vec![ ( Err ( TransactionError :: AccountNotFound ) , None ) ] ) ;
@@ -2253,8 +2248,8 @@ mod tests {
2253
2248
& mut TransactionErrorMetrics :: default ( ) ,
2254
2249
& fee_structure,
2255
2250
None ,
2256
- & ProgramCacheForTxBatch :: default ( ) ,
2257
- & HashMap :: default ( ) ,
2251
+ & [ ] ,
2252
+ & mut HashMap :: default ( ) ,
2258
2253
) ;
2259
2254
2260
2255
assert_eq ! (
0 commit comments