#![forbid(unsafe_code)]
#[path = "common/mod.rs"]
mod common;
use std::path::Path;
use dig_blockstore::constants::ALL_COLUMN_FAMILIES;
use dig_blockstore::encoding::height_key;
use dig_blockstore::{BlockStore, CF_CANONICAL};
use common::{build_chain, temp_blockstore_dir, test_config};
fn open_opts_write() -> rocksdb::Options {
let mut o = rocksdb::Options::default();
o.create_if_missing(true);
o.create_missing_column_families(true);
o
}
fn delete_cf_canonical_at_height(path: &Path, height: u64) {
let cfs: Vec<_> = ALL_COLUMN_FAMILIES
.iter()
.map(|n| rocksdb::ColumnFamilyDescriptor::new(*n, rocksdb::Options::default()))
.collect();
let db = rocksdb::DB::open_cf_descriptors(&open_opts_write(), path, cfs).expect("open for gap");
let cf = db.cf_handle(CF_CANONICAL).expect("cf canonical");
db.delete_cf(cf, height_key(height).as_slice())
.expect("delete_cf canonical row");
}
#[test]
fn test_blocks_in_range_empty() {
let (_guard, path) = temp_blockstore_dir();
let store = BlockStore::open(test_config(path)).expect("open");
let v = store.get_blocks_in_range(7, 3).expect("query");
assert!(v.is_empty());
}
#[test]
fn test_blocks_in_range_basic() {
let (_guard, path) = temp_blockstore_dir();
let store = BlockStore::open(test_config(path)).expect("open");
let chain = build_chain(10);
for b in &chain {
assert!(store.put_block(b, true).expect("put"));
}
let got = store.get_blocks_in_range(3, 7).expect("range");
assert_eq!(got.len(), 5);
for (i, b) in got.iter().enumerate() {
assert_eq!(b.height(), 3 + i as u64);
}
}
#[test]
fn test_blocks_in_range_full() {
let (_guard, path) = temp_blockstore_dir();
let store = BlockStore::open(test_config(path)).expect("open");
let chain = build_chain(10);
for b in &chain {
assert!(store.put_block(b, true).expect("put"));
}
let got = store.get_blocks_in_range(0, 9).expect("range");
assert_eq!(got.len(), 10);
assert_eq!(got[0].height(), 0);
assert_eq!(got[9].height(), 9);
}
#[test]
fn test_blocks_in_range_beyond_tip() {
let (_guard, path) = temp_blockstore_dir();
let store = BlockStore::open(test_config(path)).expect("open");
let chain = build_chain(10);
for b in &chain {
assert!(store.put_block(b, true).expect("put"));
}
let got = store.get_blocks_in_range(0, 20).expect("range");
assert_eq!(got.len(), 10);
}
#[test]
fn test_blocks_in_range_single() {
let (_guard, path) = temp_blockstore_dir();
let store = BlockStore::open(test_config(path)).expect("open");
let chain = build_chain(10);
for b in &chain {
assert!(store.put_block(b, true).expect("put"));
}
let got = store.get_blocks_in_range(5, 5).expect("range");
assert_eq!(got.len(), 1);
assert_eq!(got[0].height(), 5);
}
#[test]
fn test_blocks_in_range_skips_canonical_gap() {
let (_guard, path) = temp_blockstore_dir();
let cfg = test_config(path.clone());
let store = BlockStore::open(cfg.clone()).expect("open");
let chain = build_chain(10);
for b in &chain {
assert!(store.put_block(b, true).expect("put"));
}
drop(store);
delete_cf_canonical_at_height(&path, 5);
let store = BlockStore::open(cfg).expect("reopen");
let got = store.get_blocks_in_range(3, 7).expect("range");
assert_eq!(got.len(), 4);
assert_eq!(got[0].height(), 3);
assert_eq!(got[1].height(), 4);
assert_eq!(got[2].height(), 6);
assert_eq!(got[3].height(), 7);
}