solana_runtime/
account_info.rs1use crate::{
6 accounts_db::{AppendVecId, CACHE_VIRTUAL_OFFSET},
7 accounts_index::{IsCached, ZeroLamport},
8 append_vec::ALIGN_BOUNDARY_OFFSET,
9};
10
11pub type Offset = usize;
13
14pub type StoredSize = u32;
17
18#[derive(Debug)]
20pub enum StorageLocation {
21 AppendVec(AppendVecId, Offset),
22 Cached,
23}
24
25impl StorageLocation {
26 pub fn is_offset_equal(&self, other: &StorageLocation) -> bool {
27 match self {
28 StorageLocation::Cached => {
29 matches!(other, StorageLocation::Cached) }
31 StorageLocation::AppendVec(_, offset) => {
32 match other {
33 StorageLocation::Cached => {
34 false }
36 StorageLocation::AppendVec(_, other_offset) => other_offset == offset,
37 }
38 }
39 }
40 }
41 pub fn is_store_id_equal(&self, other: &StorageLocation) -> bool {
42 match self {
43 StorageLocation::Cached => {
44 matches!(other, StorageLocation::Cached) }
46 StorageLocation::AppendVec(store_id, _) => {
47 match other {
48 StorageLocation::Cached => {
49 false }
51 StorageLocation::AppendVec(other_store_id, _) => other_store_id == store_id,
52 }
53 }
54 }
55 }
56}
57
58pub type OffsetReduced = u32;
62
63#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
64pub struct AccountInfo {
65 store_id: AppendVecId,
67
68 reduced_offset: OffsetReduced,
71
72 stored_size_mask: StoredSize,
77}
78
79const IS_ZERO_LAMPORT_FLAG: StoredSize = 1 << (StoredSize::BITS - 1);
83const IS_CACHED_STORE_ID_FLAG: StoredSize = 1 << (StoredSize::BITS - 2);
85const ALL_FLAGS: StoredSize = IS_ZERO_LAMPORT_FLAG | IS_CACHED_STORE_ID_FLAG;
86
87impl ZeroLamport for AccountInfo {
88 fn is_zero_lamport(&self) -> bool {
89 self.stored_size_mask & IS_ZERO_LAMPORT_FLAG == IS_ZERO_LAMPORT_FLAG
90 }
91}
92
93impl IsCached for AccountInfo {
94 fn is_cached(&self) -> bool {
95 self.stored_size_mask & IS_CACHED_STORE_ID_FLAG == IS_CACHED_STORE_ID_FLAG
96 }
97}
98
99impl IsCached for StorageLocation {
100 fn is_cached(&self) -> bool {
101 matches!(self, StorageLocation::Cached)
102 }
103}
104
105const CACHE_VIRTUAL_STORAGE_ID: AppendVecId = AppendVecId::MAX;
107
108impl AccountInfo {
109 pub fn new(storage_location: StorageLocation, stored_size: StoredSize, lamports: u64) -> Self {
110 assert_eq!(stored_size & ALL_FLAGS, 0);
111 let mut stored_size_mask = stored_size;
112 let (store_id, raw_offset) = match storage_location {
113 StorageLocation::AppendVec(store_id, offset) => (store_id, offset),
114 StorageLocation::Cached => {
115 stored_size_mask |= IS_CACHED_STORE_ID_FLAG;
116 (CACHE_VIRTUAL_STORAGE_ID, CACHE_VIRTUAL_OFFSET)
117 }
118 };
119 if lamports == 0 {
120 stored_size_mask |= IS_ZERO_LAMPORT_FLAG;
121 }
122 let reduced_offset: OffsetReduced = (raw_offset / ALIGN_BOUNDARY_OFFSET) as OffsetReduced;
123 let result = Self {
124 store_id,
125 reduced_offset,
126 stored_size_mask,
127 };
128 assert_eq!(result.offset(), raw_offset, "illegal offset");
129 result
130 }
131
132 pub fn store_id(&self) -> AppendVecId {
133 assert!(!self.is_cached());
135 self.store_id
136 }
137
138 pub fn offset(&self) -> Offset {
139 (self.reduced_offset as Offset) * ALIGN_BOUNDARY_OFFSET
140 }
141
142 pub fn stored_size(&self) -> StoredSize {
143 self.stored_size_mask & !ALL_FLAGS
145 }
146
147 pub fn matches_storage_location(&self, store_id: AppendVecId, offset: Offset) -> bool {
150 self.store_id == store_id && self.offset() == offset && !self.is_cached()
152 }
153
154 pub fn storage_location(&self) -> StorageLocation {
155 if self.is_cached() {
156 StorageLocation::Cached
157 } else {
158 StorageLocation::AppendVec(self.store_id, self.offset())
159 }
160 }
161}
162#[cfg(test)]
163mod test {
164 use {super::*, crate::append_vec::MAXIMUM_APPEND_VEC_FILE_SIZE};
165
166 #[test]
167 fn test_limits() {
168 for offset in [
169 MAXIMUM_APPEND_VEC_FILE_SIZE as Offset,
170 0,
171 ALIGN_BOUNDARY_OFFSET,
172 4 * ALIGN_BOUNDARY_OFFSET,
173 ] {
174 let info = AccountInfo::new(StorageLocation::AppendVec(0, offset), 0, 0);
175 assert!(info.offset() == offset);
176 }
177 }
178
179 #[test]
180 #[should_panic(expected = "illegal offset")]
181 fn test_alignment() {
182 let offset = 1; AccountInfo::new(StorageLocation::AppendVec(0, offset), 0, 0);
184 }
185
186 #[test]
187 fn test_matches_storage_location() {
188 let offset = 0;
189 let id = 0;
190 let info = AccountInfo::new(StorageLocation::AppendVec(id, offset), 0, 0);
191 assert!(info.matches_storage_location(id, offset));
192
193 let offset = ALIGN_BOUNDARY_OFFSET;
195 assert!(!info.matches_storage_location(id, offset));
196
197 let offset = 0;
199 let id = 1;
200 assert!(!info.matches_storage_location(id, offset));
201
202 let id = CACHE_VIRTUAL_STORAGE_ID;
204 let info = AccountInfo::new(StorageLocation::Cached, 0, 0);
205 assert!(!info.matches_storage_location(id, offset));
206 }
207}