1use solana_sdk::{account::ReadableAccount, clock::Slot, pubkey::Pubkey};
3
4pub trait StorableAccounts<'a, T: ReadableAccount + Sync>: Sync {
10 fn pubkey(&self, index: usize) -> &Pubkey;
12 fn account(&self, index: usize) -> &T;
14 fn slot(&self, index: usize) -> Slot;
16 fn target_slot(&self) -> Slot;
18 fn is_empty(&self) -> bool {
20 self.len() == 0
21 }
22 fn len(&self) -> usize;
24 fn contains_multiple_slots(&self) -> bool;
27}
28
29pub struct StorableAccountsMovingSlots<'a, T: ReadableAccount + Sync> {
34 pub accounts: &'a [(&'a Pubkey, &'a T)],
35 pub target_slot: Slot,
37 pub old_slot: Slot,
39}
40
41impl<'a, T: ReadableAccount + Sync> StorableAccounts<'a, T> for StorableAccountsMovingSlots<'a, T> {
42 fn pubkey(&self, index: usize) -> &Pubkey {
43 self.accounts[index].0
44 }
45 fn account(&self, index: usize) -> &T {
46 self.accounts[index].1
47 }
48 fn slot(&self, _index: usize) -> Slot {
49 self.old_slot
51 }
52 fn target_slot(&self) -> Slot {
53 self.target_slot
54 }
55 fn len(&self) -> usize {
56 self.accounts.len()
57 }
58 fn contains_multiple_slots(&self) -> bool {
59 false
60 }
61}
62
63impl<'a, T: ReadableAccount + Sync> StorableAccounts<'a, T> for (Slot, &'a [(&'a Pubkey, &'a T)]) {
64 fn pubkey(&self, index: usize) -> &Pubkey {
65 self.1[index].0
66 }
67 fn account(&self, index: usize) -> &T {
68 self.1[index].1
69 }
70 fn slot(&self, _index: usize) -> Slot {
71 self.target_slot()
73 }
74 fn target_slot(&self) -> Slot {
75 self.0
76 }
77 fn len(&self) -> usize {
78 self.1.len()
79 }
80 fn contains_multiple_slots(&self) -> bool {
81 false
82 }
83}
84
85impl<'a, T: ReadableAccount + Sync> StorableAccounts<'a, T>
87 for (Slot, &'a [(&'a Pubkey, &'a T, Slot)])
88{
89 fn pubkey(&self, index: usize) -> &Pubkey {
90 self.1[index].0
91 }
92 fn account(&self, index: usize) -> &T {
93 self.1[index].1
94 }
95 fn slot(&self, index: usize) -> Slot {
96 self.1[index].2
98 }
99 fn target_slot(&self) -> Slot {
100 self.0
101 }
102 fn len(&self) -> usize {
103 self.1.len()
104 }
105 fn contains_multiple_slots(&self) -> bool {
106 let len = self.len();
107 if len > 0 {
108 let slot = self.slot(0);
109 (1..len).any(|i| slot != self.slot(i))
111 } else {
112 false
113 }
114 }
115}
116
117#[cfg(test)]
118pub mod tests {
119 use {
120 super::*,
121 solana_sdk::account::{AccountSharedData, WritableAccount},
122 };
123
124 fn compare<'a, T: ReadableAccount + Sync + PartialEq + std::fmt::Debug>(
125 a: &impl StorableAccounts<'a, T>,
126 b: &impl StorableAccounts<'a, T>,
127 ) {
128 assert_eq!(a.target_slot(), b.target_slot());
129 assert_eq!(a.len(), b.len());
130 assert_eq!(a.is_empty(), b.is_empty());
131 (0..a.len()).into_iter().for_each(|i| {
132 assert_eq!(a.pubkey(i), b.pubkey(i));
133 assert_eq!(a.account(i), b.account(i));
134 })
135 }
136
137 #[test]
138 fn test_contains_multiple_slots() {
139 let pk = Pubkey::from([1; 32]);
140 let account = AccountSharedData::create(1, Vec::default(), Pubkey::default(), false, 0);
141 let slot = 0;
142 let test3 = (
143 slot,
144 &vec![(&pk, &account, slot), (&pk, &account, slot)][..],
145 );
146 assert!(!(&test3).contains_multiple_slots());
147 let test3 = (
148 slot,
149 &vec![(&pk, &account, slot), (&pk, &account, slot + 1)][..],
150 );
151 assert!(test3.contains_multiple_slots());
152 }
153
154 #[test]
155 fn test_storable_accounts() {
156 let max_slots = 3_u64;
157 for target_slot in 0..max_slots {
158 for entries in 0..2 {
159 for starting_slot in 0..max_slots {
160 let mut raw = Vec::new();
161 for entry in 0..entries {
162 let pk = Pubkey::from([entry; 32]);
163 raw.push((
164 pk,
165 AccountSharedData::create(
166 ((entry as u64) * starting_slot) as u64,
167 Vec::default(),
168 Pubkey::default(),
169 false,
170 0,
171 ),
172 starting_slot % max_slots,
173 ));
174 }
175 let mut two = Vec::new();
176 let mut three = Vec::new();
177 raw.iter().for_each(|raw| {
178 two.push((&raw.0, &raw.1)); three.push((&raw.0, &raw.1, raw.2)); });
181 let test2 = (target_slot, &two[..]);
182 let test3 = (target_slot, &three[..]);
183 let old_slot = starting_slot;
184 let test_moving_slots = StorableAccountsMovingSlots {
185 accounts: &two[..],
186 target_slot,
187 old_slot,
188 };
189 compare(&test2, &test3);
190 compare(&test2, &test_moving_slots);
191 for (i, raw) in raw.iter().enumerate() {
192 assert_eq!(raw.0, *test3.pubkey(i));
193 assert_eq!(raw.1, *test3.account(i));
194 assert_eq!(raw.2, test3.slot(i));
195 assert_eq!(target_slot, test2.slot(i));
196 assert_eq!(old_slot, test_moving_slots.slot(i));
197 }
198 assert_eq!(target_slot, test3.target_slot());
199 assert!(!test2.contains_multiple_slots());
200 assert!(!test_moving_slots.contains_multiple_slots());
201 assert_eq!(test3.contains_multiple_slots(), entries > 1);
202 }
203 }
204 }
205 }
206}