mod snapshot;
pub use snapshot::FakeSnapshotMptDb;
#[cfg(test)]
mod proofs;
#[cfg(test)]
mod sharded_iter_merger;
#[cfg(test)]
mod state;
#[cfg(test)]
const TEST_NUMBER_OF_KEYS: usize = 100000;
#[derive(Default)]
pub struct FakeDbForStateTest {}
impl MallocSizeOf for FakeDbForStateTest {
fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { 0 }
}
impl KeyValueDB for FakeDbForStateTest {
fn get(&self, _col: u32, _key: &[u8]) -> std::io::Result<Option<DBValue>> {
Ok(None)
}
fn get_by_prefix(&self, _col: u32, _prefix: &[u8]) -> Option<Box<[u8]>> {
unreachable!()
}
fn write_buffered(&self, _transaction: DBTransaction) {}
fn flush(&self) -> std::io::Result<()> { Ok(()) }
fn iter<'a>(
&'a self, _col: u32,
) -> Box<dyn Iterator<Item = (Box<[u8]>, Box<[u8]>)>> {
unreachable!()
}
fn iter_from_prefix<'a>(
&'a self, _col: u32, _prefix: &'a [u8],
) -> Box<dyn Iterator<Item = (Box<[u8]>, Box<[u8]>)>> {
unreachable!()
}
fn restore(&self, _new_db: &str) -> std::io::Result<()> { unreachable!() }
}
#[cfg(any(test, feature = "testonly_code"))]
pub struct FakeStateManager {
data_dir: String,
state_manager: Option<Arc<StateManager>>,
}
#[cfg(any(test, feature = "testonly_code"))]
impl FakeStateManager {
fn new(
conflux_data_dir: String, snapshot_epoch_count: u32,
) -> Result<Self> {
let unit_test_data_dir =
conflux_data_dir + &random::<u64>().to_string();
fs::create_dir_all(unit_test_data_dir.as_str())?;
let mut storage_conf = StorageConfiguration::new_default(
&unit_test_data_dir,
snapshot_epoch_count,
20000,
);
storage_conf.delta_mpts_cache_size = 20_000_000;
storage_conf.delta_mpts_cache_start_size = 1_000_000;
storage_conf.delta_mpts_node_map_vec_size = 20_000_000;
storage_conf.delta_mpts_slab_idle_size = 200_000;
Ok(FakeStateManager {
data_dir: unit_test_data_dir,
state_manager: Some(Arc::new(StateManager::new(storage_conf)?)),
})
}
}
#[cfg(any(test, feature = "testonly_code"))]
impl Drop for FakeStateManager {
fn drop(&mut self) {
self.state_manager.take();
fs::remove_dir_all(self.data_dir.as_str()).ok();
let maybe_parent_dir = Path::new(self.data_dir.as_str()).parent();
if let Some(parent_dir) = maybe_parent_dir {
fs::remove_dir(parent_dir).ok();
}
}
}
#[cfg(any(test, feature = "testonly_code"))]
impl Deref for FakeStateManager {
type Target = Arc<StateManager>;
fn deref(&self) -> &Self::Target { self.state_manager.as_ref().unwrap() }
}
#[cfg(any(test, feature = "testonly_code"))]
impl DerefMut for FakeStateManager {
fn deref_mut(&mut self) -> &mut Self::Target {
self.state_manager.as_mut().unwrap()
}
}
#[cfg(any(test, feature = "testonly_code"))]
pub fn new_state_manager_for_unit_test_with_snapshot_epoch_count(
snapshot_epoch_count: u32,
) -> FakeStateManager {
const WITH_LOGGER: bool = false;
if WITH_LOGGER {
log4rs::init_config(
log4rs::config::Config::builder()
.appender(
log4rs::config::Appender::builder().build(
"stdout",
Box::new(
log4rs::append::console::ConsoleAppender::builder()
.build(),
),
),
)
.build(
log4rs::config::Root::builder()
.appender("stdout")
.build(log::LevelFilter::Debug),
)
.unwrap(),
)
.ok();
}
FakeStateManager::new(
"./conflux_unit_test_data_dir".to_string(),
snapshot_epoch_count,
)
.unwrap()
}
#[cfg(any(test, feature = "testonly_code"))]
pub fn new_state_manager_for_unit_test() -> FakeStateManager {
let snapshot_epoch_count = 10;
new_state_manager_for_unit_test_with_snapshot_epoch_count(
snapshot_epoch_count,
)
}
#[derive(Default)]
pub struct DumpedMptKvIterator {
pub kv: Vec<MptKeyValue>,
}
pub struct DumpedMptKvFallibleIterator {
pub kv: Vec<MptKeyValue>,
pub index: usize,
}
impl DumpedMptKvIterator {
pub fn iterate<'a, DeltaMptDumper: KVInserter<MptKeyValue>>(
&self, dumper: &mut DeltaMptDumper,
) -> Result<()> {
let mut sorted_kv = self.kv.clone();
sorted_kv.sort();
for kv_item in sorted_kv {
dumper.push(kv_item)?;
}
Ok(())
}
}
impl KVInserter<MptKeyValue> for DumpedMptKvIterator {
fn push(&mut self, v: MptKeyValue) -> Result<()> {
let (mpt_key, value) = v;
let snapshot_key =
StorageKeyWithSpace::from_delta_mpt_key(&mpt_key).to_key_bytes();
self.kv.push((snapshot_key, value));
Ok(())
}
}
impl FallibleIterator for DumpedMptKvFallibleIterator {
type Error = Error;
type Item = MptKeyValue;
fn next(&mut self) -> Result<Option<Self::Item>> {
let result = Ok(self.kv.get(self.index).cloned());
self.index += 1;
result
}
}
#[cfg(test)]
fn generate_keys(number_of_keys: usize) -> Vec<Vec<u8>> {
let mut rng = get_rng_for_test();
let mut keys_num: Vec<u64> = Default::default();
for _i in 0..number_of_keys {
keys_num.push(rng.gen());
}
keys_num.sort();
let mut keys = vec![];
let mut last_key = keys_num[0];
for key in &keys_num[1..number_of_keys] {
if *key != last_key {
keys.push(Vec::from(
&unsafe { std::mem::transmute::<u64, [u8; 8]>(key.clone()) }[..],
));
}
last_key = *key;
}
keys.shuffle(&mut rng);
keys
}
#[cfg(test)]
fn generate_account_keys(number_of_keys: usize) -> Vec<Vec<u8>> {
let mut rng = get_rng_for_test();
(0..number_of_keys)
.map(|_| rng.gen::<[u8; 20]>().to_vec())
.collect()
}
#[cfg(test)]
fn get_rng_for_test() -> ChaChaRng { ChaChaRng::from_seed([123; 32]) }
#[allow(dead_code)]
pub fn print_mpt_key(key: &[u8]) {
print!("key = (");
for char in key {
print!(
"{}, {}, ",
CompressedPathRaw::first_nibble(*char),
CompressedPathRaw::second_nibble(*char)
);
}
println!(")");
}
#[cfg(any(test, feature = "testonly_code"))]
use crate::{impls::state_manager::StateManager, StorageConfiguration};
use crate::{
impls::{
errors::*,
merkle_patricia_trie::{CompressedPathRaw, MptKeyValue},
},
KVInserter,
};
use fallible_iterator::FallibleIterator;
use kvdb::{DBTransaction, DBValue, KeyValueDB};
use parity_util_mem::{MallocSizeOf, MallocSizeOfOps};
use primitives::StorageKeyWithSpace;
#[cfg(any(test, feature = "testonly_code"))]
use rand::random;
#[cfg(test)]
use rand::{seq::SliceRandom, Rng, SeedableRng};
#[cfg(test)]
use rand_chacha::ChaChaRng;
#[cfg(any(test, feature = "testonly_code"))]
use std::{
fs,
ops::{Deref, DerefMut},
path::Path,
sync::Arc,
};