1mod snapshot;
6pub use snapshot::FakeSnapshotMptDb;
7
8#[cfg(test)]
9mod proofs;
10#[cfg(test)]
11mod sharded_iter_merger;
12#[cfg(test)]
13mod state;
14
15#[cfg(test)]
16const TEST_NUMBER_OF_KEYS: usize = 100000;
17
18#[derive(Default)]
19pub struct FakeDbForStateTest {}
20
21impl KeyValueDB for FakeDbForStateTest {
22 fn get(&self, _col: u32, _key: &[u8]) -> std::io::Result<Option<DBValue>> {
23 Ok(None)
24 }
25
26 fn get_by_prefix(
27 &self, _col: u32, _prefix: &[u8],
28 ) -> std::io::Result<Option<DBValue>> {
29 unreachable!()
30 }
31
32 fn write(&self, _transaction: DBTransaction) -> std::io::Result<()> {
33 Ok(())
34 }
35
36 fn iter<'a>(
37 &'a self, _col: u32,
38 ) -> Box<dyn Iterator<Item = std::io::Result<kvdb::DBKeyValue>> + 'a> {
39 unreachable!()
40 }
41
42 fn iter_with_prefix<'a>(
43 &'a self, _col: u32, _prefix: &'a [u8],
44 ) -> Box<dyn Iterator<Item = std::io::Result<kvdb::DBKeyValue>> + 'a> {
45 unreachable!()
46 }
47}
48
49#[cfg(any(test, feature = "testonly_code"))]
50pub struct FakeStateManager {
51 data_dir: String,
52 state_manager: Option<Arc<StateManager>>,
53}
54
55#[cfg(any(test, feature = "testonly_code"))]
56impl FakeStateManager {
57 fn new(
58 conflux_data_dir: String, snapshot_epoch_count: u32,
59 ) -> Result<Self> {
60 let unit_test_data_dir =
63 conflux_data_dir + &random::<u64>().to_string();
64 fs::create_dir_all(unit_test_data_dir.as_str())?;
65 let mut storage_conf = StorageConfiguration::new_default(
66 &unit_test_data_dir,
67 snapshot_epoch_count,
68 20000,
69 );
70 storage_conf.delta_mpts_cache_size = 20_000_000;
71 storage_conf.delta_mpts_cache_start_size = 1_000_000;
72 storage_conf.delta_mpts_node_map_vec_size = 20_000_000;
73 storage_conf.delta_mpts_slab_idle_size = 200_000;
74
75 Ok(FakeStateManager {
76 data_dir: unit_test_data_dir,
77 state_manager: Some(Arc::new(StateManager::new(storage_conf)?)),
78 })
79 }
80}
81
82#[cfg(any(test, feature = "testonly_code"))]
83impl Drop for FakeStateManager {
84 fn drop(&mut self) {
85 self.state_manager.take();
86 fs::remove_dir_all(self.data_dir.as_str()).ok();
87 let maybe_parent_dir = Path::new(self.data_dir.as_str()).parent();
88 if let Some(parent_dir) = maybe_parent_dir {
89 fs::remove_dir(parent_dir).ok();
90 }
91 }
92}
93
94#[cfg(any(test, feature = "testonly_code"))]
95impl Deref for FakeStateManager {
96 type Target = Arc<StateManager>;
97
98 fn deref(&self) -> &Self::Target { self.state_manager.as_ref().unwrap() }
99}
100
101#[cfg(any(test, feature = "testonly_code"))]
102impl DerefMut for FakeStateManager {
103 fn deref_mut(&mut self) -> &mut Self::Target {
104 self.state_manager.as_mut().unwrap()
105 }
106}
107
108#[cfg(any(test, feature = "testonly_code"))]
109pub fn new_state_manager_for_unit_test_with_snapshot_epoch_count(
110 snapshot_epoch_count: u32,
111) -> FakeStateManager {
112 const WITH_LOGGER: bool = false;
113 if WITH_LOGGER {
114 log4rs::init_config(
115 log4rs::config::Config::builder()
116 .appender(
117 log4rs::config::Appender::builder().build(
118 "stdout",
119 Box::new(
120 log4rs::append::console::ConsoleAppender::builder()
121 .build(),
122 ),
123 ),
124 )
125 .build(
126 log4rs::config::Root::builder()
127 .appender("stdout")
128 .build(log::LevelFilter::Debug),
129 )
130 .unwrap(),
131 )
132 .ok();
133 }
134
135 FakeStateManager::new(
136 "./conflux_unit_test_data_dir".to_string(),
137 snapshot_epoch_count,
138 )
139 .unwrap()
140}
141
142#[cfg(any(test, feature = "testonly_code"))]
143pub fn new_state_manager_for_unit_test() -> FakeStateManager {
144 let snapshot_epoch_count = 10;
145 new_state_manager_for_unit_test_with_snapshot_epoch_count(
146 snapshot_epoch_count,
147 )
148}
149
150#[derive(Default)]
151pub struct DumpedMptKvIterator {
152 pub kv: Vec<MptKeyValue>,
153}
154
155pub struct DumpedMptKvFallibleIterator {
156 pub kv: Vec<MptKeyValue>,
157 pub index: usize,
158}
159
160impl DumpedMptKvIterator {
161 pub fn iterate<'a, DeltaMptDumper: KVInserter<MptKeyValue>>(
162 &self, dumper: &mut DeltaMptDumper,
163 ) -> Result<()> {
164 let mut sorted_kv = self.kv.clone();
165 sorted_kv.sort();
166 for kv_item in sorted_kv {
167 dumper.push(kv_item)?;
168 }
169 Ok(())
170 }
171}
172
173impl KVInserter<MptKeyValue> for DumpedMptKvIterator {
174 fn push(&mut self, v: MptKeyValue) -> Result<()> {
175 let (mpt_key, value) = v;
176 let snapshot_key =
177 StorageKeyWithSpace::from_delta_mpt_key(&mpt_key).to_key_bytes();
178
179 self.kv.push((snapshot_key, value));
180 Ok(())
181 }
182}
183
184impl FallibleIterator for DumpedMptKvFallibleIterator {
185 type Error = Error;
186 type Item = MptKeyValue;
187
188 fn next(&mut self) -> Result<Option<Self::Item>> {
189 let result = Ok(self.kv.get(self.index).cloned());
190 self.index += 1;
191 result
192 }
193}
194
195#[cfg(test)]
196fn generate_keys(number_of_keys: usize) -> Vec<Vec<u8>> {
197 let mut rng = get_rng_for_test();
198
199 let mut keys_num: Vec<u64> = Default::default();
200
201 for _i in 0..number_of_keys {
202 keys_num.push(rng.gen());
203 }
204
205 keys_num.sort();
206
207 let mut keys = vec![];
208 let mut last_key = keys_num[0];
209 for key in &keys_num[1..number_of_keys] {
210 if *key != last_key {
211 keys.push(Vec::from(key.to_ne_bytes()));
212 }
213 last_key = *key;
214 }
215
216 keys.shuffle(&mut rng);
217 keys
218}
219
220#[cfg(test)]
221fn generate_account_keys(number_of_keys: usize) -> Vec<Vec<u8>> {
222 let mut rng = get_rng_for_test();
223 (0..number_of_keys)
224 .map(|_| rng.gen::<[u8; 20]>().to_vec())
225 .collect()
226}
227
228#[cfg(test)]
229fn get_rng_for_test() -> ChaChaRng { ChaChaRng::from_seed([123; 32]) }
230
231#[allow(dead_code)]
233pub fn print_mpt_key(key: &[u8]) {
234 print!("key = (");
235 for char in key {
236 print!(
237 "{}, {}, ",
238 CompressedPathRaw::first_nibble(*char),
239 CompressedPathRaw::second_nibble(*char)
240 );
241 }
242 println!(")");
243}
244
245#[cfg(any(test, feature = "testonly_code"))]
246use crate::{impls::state_manager::StateManager, StorageConfiguration};
247use crate::{
248 impls::{
249 errors::*,
250 merkle_patricia_trie::{CompressedPathRaw, MptKeyValue},
251 },
252 KVInserter,
253};
254use fallible_iterator::FallibleIterator;
255use kvdb::{DBTransaction, DBValue, KeyValueDB};
256use primitives::StorageKeyWithSpace;
257#[cfg(any(test, feature = "testonly_code"))]
258use rand::random;
259#[cfg(test)]
260use rand::{seq::SliceRandom, Rng, SeedableRng};
261#[cfg(test)]
262use rand_chacha::ChaChaRng;
263#[cfg(any(test, feature = "testonly_code"))]
264use std::{
265 fs,
266 ops::{Deref, DerefMut},
267 path::Path,
268 sync::Arc,
269};