use std::{sync::Arc, thread};
use parking_lot::RwLock;
use skippydb::{
config::Config,
def::{ENTRY_BASE_LENGTH, IN_BLOCK_IDX_BITS, TWIG_MASK},
entryfile::entry,
merkletree::{
check,
helpers::build_test_tree,
proof::{self, check_proof, ProofPath},
},
seqads::task::{SingleCsTask, TaskBuilder},
tasks::TasksManager,
test_helper::TempDir,
AdsCore, AdsWrap, ADS,
};
fn check_equal(pp: &ProofPath, other: &ProofPath) -> String {
if pp.upper_path.len() != other.upper_path.len() {
return String::from("UpperPath's length not equal");
}
if pp.serial_num != other.serial_num {
return String::from("SerialNum not equal");
}
if pp.left_of_twig[0].self_hash != other.left_of_twig[0].self_hash {
return String::from("LeftOfTwig.SelfHash not equal");
}
for i in 0..11 {
if pp.left_of_twig[i].peer_hash != other.left_of_twig[i].peer_hash {
return String::from("LeftOfTwig.PeerHash not equal");
}
if pp.left_of_twig[i].peer_at_left != other.left_of_twig[i].peer_at_left {
return format!("LeftOfTwig.PeerAtLeft[{}] not equal", i);
}
}
if pp.right_of_twig[0].self_hash != other.right_of_twig[0].self_hash {
return String::from("RightOfTwig.SelfHash not equal");
}
for i in 0..3 {
if pp.right_of_twig[i].peer_hash != other.right_of_twig[i].peer_hash {
return String::from("RightOfTwig.PeerHash not equal");
}
if pp.right_of_twig[i].peer_at_left != other.right_of_twig[i].peer_at_left {
return String::from("RightOfTwig.PeerAtLeft not equal");
}
}
for i in 0..pp.upper_path.len() {
if pp.upper_path[i].peer_hash != other.upper_path[i].peer_hash {
return String::from("UpperPath.PeerHash not equal");
}
if pp.upper_path[i].peer_at_left != other.upper_path[i].peer_at_left {
return String::from("UpperPath.PeerAtLeft not equal");
}
}
if pp.root != other.root {
return String::from("Root not equal");
}
String::from("")
}
#[test]
fn test_tree_proof() {
let dir_name = "./DataTree-proof";
let _tmp_dir = TempDir::new(dir_name);
let deact_sn_list: Vec<u64> = (0..2048)
.chain(vec![5000, 5500, 5700, 5813, 6001])
.collect();
let (mut tree, _, _, _) = build_test_tree(dir_name, &deact_sn_list, TWIG_MASK as i32 * 4, 1600);
let n_list = tree.flush_files(0, 0);
let n_list = tree.upper_tree.evict_twigs(n_list, 0, 0);
tree.upper_tree
.sync_upper_nodes(n_list, tree.youngest_twig_id);
check::check_hash_consistency(&tree);
let max_sn = TWIG_MASK as i32 * 4 + 1600;
for i in 0..max_sn {
let mut proof_path = tree.get_proof(i as u64).unwrap();
proof_path.check(false).unwrap();
let bz = proof_path.to_bytes();
let mut path2 = proof::bytes_to_proof_path(&bz).unwrap();
let r = check_equal(&proof_path, &path2);
assert_eq!(r, String::from(""));
path2.check(true).unwrap();
}
let _max_sn = max_sn + 452;
let mut bz = [0u8; ENTRY_BASE_LENGTH + 8];
let null_hash = entry::null_entry(&mut bz[..]).hash();
for i in max_sn.._max_sn {
let mut proof_path = tree.get_proof(i as u64).unwrap();
assert_eq!(proof_path.left_of_twig[0].self_hash, null_hash);
proof_path.check(false).unwrap();
let bz = proof_path.to_bytes();
let mut path2 = proof::bytes_to_proof_path(&bz).unwrap();
let r = check_equal(&proof_path, &path2);
assert_eq!(r, String::from(""));
path2.check(true).unwrap();
}
}
#[test]
fn test_tree_get_proof() {
let ads_dir = "./test_tree_get_proof";
let _tmp_dir = TempDir::new(ads_dir);
let mut config = Config::from_dir(ads_dir);
AdsCore::init_dir(&config);
config.set_with_twig_file(true);
let mut ads = Box::new(AdsWrap::new(&config));
let ads_p = &mut *ads as *mut AdsWrap<SingleCsTask>;
let handle = thread::spawn(move || {
let mut proof = ads.get_proof(5, 4096).unwrap();
assert_eq!(
proof.left_of_twig[0].self_hash,
[
93, 178, 212, 56, 37, 103, 172, 205, 255, 184, 39, 231, 94, 228, 14, 210, 209, 165,
122, 253, 187, 100, 5, 13, 55, 169, 246, 181, 247, 201, 159, 152
]
);
check_proof(&mut proof).unwrap();
});
unsafe {
let ads = &mut (*ads_p);
let task_id = 1 << IN_BLOCK_IDX_BITS;
ads.start_block(
1,
Arc::new(TasksManager::new(
vec![RwLock::new(Some(
TaskBuilder::new().create(b"k12", b"v1").build(),
))],
task_id,
)),
);
let shared_ads = ads.get_shared();
shared_ads.insert_extra_data(1, "".to_owned());
shared_ads.add_task(task_id);
}
handle.join().unwrap();
}
#[test]
fn test_tree_get_proof_err() {
let ads_dir = "./test_tree_get_proof_err";
let _tmp_dir = TempDir::new(ads_dir);
let config = Config::from_dir(ads_dir);
AdsCore::init_dir(&config);
let mut ads = Box::new(AdsWrap::new(&config));
let ads_p = &mut *ads as *mut AdsWrap<SingleCsTask>;
let handle = thread::spawn(move || {
let proof = ads.get_proof(5, 4095);
assert!(proof.is_err());
if let Err(e) = proof {
assert_eq!(e, format!("get proof failed: \"twig_file is empty\""));
}
});
unsafe {
let ads = &mut (*ads_p);
let task_id = 1 << IN_BLOCK_IDX_BITS;
ads.start_block(
1,
Arc::new(TasksManager::new(
vec![RwLock::new(Some(
TaskBuilder::new().create(b"k12", b"v1").build(),
))],
task_id,
)),
);
let shared_ads = ads.get_shared();
shared_ads.insert_extra_data(1, "".to_owned());
shared_ads.add_task(task_id);
}
handle.join().unwrap();
}