|
42 | 42 | get_ancient_append_vec_capacity, is_ancient, AccountsToStore, StorageSelector,
|
43 | 43 | },
|
44 | 44 | append_vec::{
|
45 |
| - aligned_stored_size, AppendVec, StorableAccountsWithHashesAndWriteVersions, |
46 |
| - StoredAccountMeta, StoredMetaWriteVersion, APPEND_VEC_MMAPPED_FILES_OPEN, |
47 |
| - STORE_META_OVERHEAD, |
| 45 | + aligned_stored_size, AppendVec, MatchAccountOwnerError, |
| 46 | + StorableAccountsWithHashesAndWriteVersions, StoredAccountMeta, StoredMetaWriteVersion, |
| 47 | + APPEND_VEC_MMAPPED_FILES_OPEN, STORE_META_OVERHEAD, |
48 | 48 | },
|
49 | 49 | cache_hash_data::{CacheHashData, CacheHashDataFile},
|
50 | 50 | contains::Contains,
|
@@ -815,6 +815,32 @@ impl<'a> LoadedAccountAccessor<'a> {
|
815 | 815 | }
|
816 | 816 | }
|
817 | 817 | }
|
| 818 | + |
| 819 | + fn account_matches_owners(&self, owners: &[&Pubkey]) -> Result<(), MatchAccountOwnerError> { |
| 820 | + match self { |
| 821 | + LoadedAccountAccessor::Cached(cached_account) => cached_account |
| 822 | + .as_ref() |
| 823 | + .and_then(|cached_account| { |
| 824 | + (!cached_account.account.is_zero_lamport() |
| 825 | + && owners.contains(&cached_account.account.owner())) |
| 826 | + .then_some(()) |
| 827 | + }) |
| 828 | + .ok_or(MatchAccountOwnerError::NoMatch), |
| 829 | + LoadedAccountAccessor::Stored(maybe_storage_entry) => { |
| 830 | + // storage entry may not be present if slot was cleaned up in |
| 831 | + // between reading the accounts index and calling this function to |
| 832 | + // get account meta from the storage entry here |
| 833 | + maybe_storage_entry |
| 834 | + .as_ref() |
| 835 | + .map(|(storage_entry, offset)| { |
| 836 | + storage_entry |
| 837 | + .accounts |
| 838 | + .account_matches_owners(*offset, owners) |
| 839 | + }) |
| 840 | + .unwrap_or(Err(MatchAccountOwnerError::UnableToLoad)) |
| 841 | + } |
| 842 | + } |
| 843 | + } |
818 | 844 | }
|
819 | 845 |
|
820 | 846 | pub enum LoadedAccount<'a> {
|
@@ -4918,6 +4944,38 @@ impl AccountsDb {
|
4918 | 4944 | self.do_load(ancestors, pubkey, None, load_hint, LoadZeroLamports::None)
|
4919 | 4945 | }
|
4920 | 4946 |
|
| 4947 | + pub fn account_matches_owners( |
| 4948 | + &self, |
| 4949 | + ancestors: &Ancestors, |
| 4950 | + account: &Pubkey, |
| 4951 | + owners: &[&Pubkey], |
| 4952 | + ) -> Result<(), MatchAccountOwnerError> { |
| 4953 | + let (slot, storage_location, _maybe_account_accesor) = self |
| 4954 | + .read_index_for_accessor_or_load_slow(ancestors, account, None, false) |
| 4955 | + .ok_or(MatchAccountOwnerError::UnableToLoad)?; |
| 4956 | + |
| 4957 | + if !storage_location.is_cached() { |
| 4958 | + let result = self.read_only_accounts_cache.load(*account, slot); |
| 4959 | + if let Some(account) = result { |
| 4960 | + return (!account.is_zero_lamport() && owners.contains(&account.owner())) |
| 4961 | + .then_some(()) |
| 4962 | + .ok_or(MatchAccountOwnerError::NoMatch); |
| 4963 | + } |
| 4964 | + } |
| 4965 | + |
| 4966 | + let (account_accessor, _slot) = self |
| 4967 | + .retry_to_get_account_accessor( |
| 4968 | + slot, |
| 4969 | + storage_location, |
| 4970 | + ancestors, |
| 4971 | + account, |
| 4972 | + None, |
| 4973 | + LoadHint::Unspecified, |
| 4974 | + ) |
| 4975 | + .ok_or(MatchAccountOwnerError::UnableToLoad)?; |
| 4976 | + account_accessor.account_matches_owners(owners) |
| 4977 | + } |
| 4978 | + |
4921 | 4979 | pub fn load_account_into_read_cache(&self, ancestors: &Ancestors, pubkey: &Pubkey) {
|
4922 | 4980 | self.do_load_with_populate_read_cache(
|
4923 | 4981 | ancestors,
|
@@ -14068,6 +14126,101 @@ pub mod tests {
|
14068 | 14126 | assert_eq!(db.read_only_accounts_cache.cache_len(), 1);
|
14069 | 14127 | }
|
14070 | 14128 |
|
| 14129 | + #[test] |
| 14130 | + fn test_account_matches_owners() { |
| 14131 | + let db = Arc::new(AccountsDb::new_with_config_for_tests( |
| 14132 | + Vec::new(), |
| 14133 | + &ClusterType::Development, |
| 14134 | + AccountSecondaryIndexes::default(), |
| 14135 | + AccountShrinkThreshold::default(), |
| 14136 | + )); |
| 14137 | + |
| 14138 | + let owners: Vec<Pubkey> = (0..2).map(|_| Pubkey::new_unique()).collect(); |
| 14139 | + let owners_refs: Vec<&Pubkey> = owners.iter().collect(); |
| 14140 | + |
| 14141 | + let account1_key = Pubkey::new_unique(); |
| 14142 | + let account1 = AccountSharedData::new(321, 10, &owners[0]); |
| 14143 | + |
| 14144 | + let account2_key = Pubkey::new_unique(); |
| 14145 | + let account2 = AccountSharedData::new(1, 1, &owners[1]); |
| 14146 | + |
| 14147 | + let account3_key = Pubkey::new_unique(); |
| 14148 | + let account3 = AccountSharedData::new(1, 1, &Pubkey::new_unique()); |
| 14149 | + |
| 14150 | + // Account with 0 lamports |
| 14151 | + let account4_key = Pubkey::new_unique(); |
| 14152 | + let account4 = AccountSharedData::new(0, 1, &owners[1]); |
| 14153 | + |
| 14154 | + db.store_cached((0, &[(&account1_key, &account1)][..]), None); |
| 14155 | + db.store_cached((1, &[(&account2_key, &account2)][..]), None); |
| 14156 | + db.store_cached((2, &[(&account3_key, &account3)][..]), None); |
| 14157 | + db.store_cached((3, &[(&account4_key, &account4)][..]), None); |
| 14158 | + |
| 14159 | + db.add_root(0); |
| 14160 | + db.add_root(1); |
| 14161 | + db.add_root(2); |
| 14162 | + db.add_root(3); |
| 14163 | + |
| 14164 | + // Flush the cache so that the account meta will be read from the storage |
| 14165 | + db.flush_accounts_cache(true, None); |
| 14166 | + db.clean_accounts_for_tests(); |
| 14167 | + |
| 14168 | + assert_eq!( |
| 14169 | + db.account_matches_owners(&Ancestors::default(), &account1_key, &owners_refs), |
| 14170 | + Ok(()) |
| 14171 | + ); |
| 14172 | + assert_eq!( |
| 14173 | + db.account_matches_owners(&Ancestors::default(), &account2_key, &owners_refs), |
| 14174 | + Ok(()) |
| 14175 | + ); |
| 14176 | + assert_eq!( |
| 14177 | + db.account_matches_owners(&Ancestors::default(), &account3_key, &owners_refs), |
| 14178 | + Err(MatchAccountOwnerError::NoMatch) |
| 14179 | + ); |
| 14180 | + assert_eq!( |
| 14181 | + db.account_matches_owners(&Ancestors::default(), &account4_key, &owners_refs), |
| 14182 | + Err(MatchAccountOwnerError::NoMatch) |
| 14183 | + ); |
| 14184 | + assert_eq!( |
| 14185 | + db.account_matches_owners(&Ancestors::default(), &Pubkey::new_unique(), &owners_refs), |
| 14186 | + Err(MatchAccountOwnerError::UnableToLoad) |
| 14187 | + ); |
| 14188 | + |
| 14189 | + // Flush the cache and load account1 (so that it's in the cache) |
| 14190 | + db.flush_accounts_cache(true, None); |
| 14191 | + db.clean_accounts_for_tests(); |
| 14192 | + let _ = db |
| 14193 | + .do_load( |
| 14194 | + &Ancestors::default(), |
| 14195 | + &account1_key, |
| 14196 | + Some(0), |
| 14197 | + LoadHint::Unspecified, |
| 14198 | + LoadZeroLamports::SomeWithZeroLamportAccountForTests, |
| 14199 | + ) |
| 14200 | + .unwrap(); |
| 14201 | + |
| 14202 | + assert_eq!( |
| 14203 | + db.account_matches_owners(&Ancestors::default(), &account1_key, &owners_refs), |
| 14204 | + Ok(()) |
| 14205 | + ); |
| 14206 | + assert_eq!( |
| 14207 | + db.account_matches_owners(&Ancestors::default(), &account2_key, &owners_refs), |
| 14208 | + Ok(()) |
| 14209 | + ); |
| 14210 | + assert_eq!( |
| 14211 | + db.account_matches_owners(&Ancestors::default(), &account3_key, &owners_refs), |
| 14212 | + Err(MatchAccountOwnerError::NoMatch) |
| 14213 | + ); |
| 14214 | + assert_eq!( |
| 14215 | + db.account_matches_owners(&Ancestors::default(), &account4_key, &owners_refs), |
| 14216 | + Err(MatchAccountOwnerError::NoMatch) |
| 14217 | + ); |
| 14218 | + assert_eq!( |
| 14219 | + db.account_matches_owners(&Ancestors::default(), &Pubkey::new_unique(), &owners_refs), |
| 14220 | + Err(MatchAccountOwnerError::UnableToLoad) |
| 14221 | + ); |
| 14222 | + } |
| 14223 | + |
14071 | 14224 | /// a test that will accept either answer
|
14072 | 14225 | const LOAD_ZERO_LAMPORTS_ANY_TESTS: LoadZeroLamports = LoadZeroLamports::None;
|
14073 | 14226 |
|
|
0 commit comments