mod helpers;
use dig_coinstore::coin_store::CoinStore;
use dig_coinstore::merkle::{empty_hash, SMT_HEIGHT};
use dig_coinstore::{Bytes32, CoinStoreStats};
#[test]
fn vv_req_api_007_coin_store_stats_struct_all_fields_accessible() {
let s = CoinStoreStats {
height: 9,
timestamp: 88,
unspent_count: 10,
spent_count: 2,
total_unspent_value: 1_234,
state_root: Bytes32::from([0xAB; 32]),
tip_hash: Bytes32::from([0xCD; 32]),
hint_count: 3,
snapshot_count: 4,
};
assert_eq!(s.height, 9);
assert_eq!(s.timestamp, 88);
assert_eq!(s.unspent_count, 10);
assert_eq!(s.spent_count, 2);
assert_eq!(s.total_unspent_value, 1_234);
assert_eq!(s.state_root, Bytes32::from([0xAB; 32]));
assert_eq!(s.tip_hash, Bytes32::from([0xCD; 32]));
assert_eq!(s.hint_count, 3);
assert_eq!(s.snapshot_count, 4);
}
#[cfg(feature = "rocksdb-storage")]
#[test]
fn vv_req_api_007_stats_fresh_uninitialized_all_zeros() {
let dir = helpers::temp_dir();
let store = CoinStore::new(dir.path()).unwrap();
let s = store.stats();
assert_eq!(s.height, 0);
assert_eq!(s.timestamp, 0);
assert_eq!(s.unspent_count, 0);
assert_eq!(s.spent_count, 0);
assert_eq!(s.total_unspent_value, 0);
assert_eq!(s.tip_hash, Bytes32::from([0u8; 32]));
assert_eq!(s.hint_count, 0);
assert_eq!(s.snapshot_count, 0);
assert_eq!(
s.state_root,
empty_hash(SMT_HEIGHT),
"empty Merkle tree root (MRK-002)"
);
}
#[cfg(feature = "rocksdb-storage")]
#[test]
fn vv_req_api_007_stats_after_empty_genesis() {
let dir = helpers::temp_dir();
let mut store = CoinStore::new(dir.path()).unwrap();
store.init_genesis(vec![], 1_700_000_000).unwrap();
let s = store.stats();
assert_eq!(s.unspent_count, 0);
assert_eq!(s.spent_count, 0);
assert_eq!(s.total_unspent_value, 0);
assert_eq!(s.height, 0);
assert_eq!(s.timestamp, store.timestamp());
}
#[cfg(feature = "rocksdb-storage")]
#[test]
fn vv_req_api_007_stats_after_genesis_three_coins() {
let dir = helpers::temp_dir();
let mut store = CoinStore::new(dir.path()).unwrap();
let c1 = helpers::test_coin(1, 2, 100);
let c2 = helpers::test_coin(3, 4, 200);
let c3 = helpers::test_coin(5, 6, 300);
store
.init_genesis(vec![(c1, false), (c2, true), (c3, false)], 1_700_000_001)
.unwrap();
let s = store.stats();
assert_eq!(s.unspent_count, 3, "three live rows in coin_records");
assert_eq!(s.spent_count, 0);
assert_eq!(s.total_unspent_value, 600, "100 + 200 + 300 mojos");
assert_eq!(s.height, 0);
assert_eq!(s.timestamp, 1_700_000_001);
}
#[cfg(feature = "rocksdb-storage")]
#[test]
fn vv_req_api_007_stats_matches_accessors_and_state_root() {
let dir = helpers::temp_dir();
let mut store = CoinStore::new(dir.path()).unwrap();
store
.init_genesis(vec![(helpers::test_coin(9, 8, 42), false)], 1_700_000_002)
.unwrap();
let s = store.stats();
assert_eq!(s.height, store.height());
assert_eq!(s.timestamp, store.timestamp());
assert_eq!(s.tip_hash, store.tip_hash());
assert_eq!(s.state_root, store.state_root());
}
#[test]
fn vv_req_api_007_coin_store_stats_clone_debug_bincode() {
let s = CoinStoreStats {
height: 1,
timestamp: 2,
unspent_count: 3,
spent_count: 4,
total_unspent_value: 5,
state_root: Bytes32::from([1u8; 32]),
tip_hash: Bytes32::from([2u8; 32]),
hint_count: 6,
snapshot_count: 7,
};
let c = s.clone();
assert_eq!(c, s);
let dbg = format!("{s:?}");
assert!(!dbg.is_empty(), "Debug must be non-empty for ops logging");
let bytes = bincode::serialize(&s).expect("serialize CoinStoreStats");
let back: CoinStoreStats = bincode::deserialize(&bytes).expect("deserialize");
assert_eq!(back, s);
}