use electrs_client::{BlockMeta, Client, Update, UpdateCapable};
use itertools::Itertools;
use nintypes::external::previewer::PreviewerBlockData;
type TestCache = PreviewerBlockData;
type TestFetched = Vec<PreviewerBlockData>;
async fn prepare() -> Client<TestCache> {
dotenv::dotenv().ok();
unsafe { std::env::set_var("EC_REORGS_PATH", "./test_cache") };
let c = Client::new().await.unwrap();
assert!(
c.is_alive::<TestFetched>().await,
"failed to connect to client"
);
c
}
#[tokio::test]
async fn vlad() {
let client = prepare().await;
let from = [
client.get_electrs_block_meta(4655000).await.unwrap(),
];
dbg!(&from);
let updates = client
.fetch_updates::<TestFetched>(&from)
.await
.inspect_err(|e| {
dbg!(e);
})
.unwrap();
let (new_blocks, reorgs) = updates.iter().fold((0, 0), |(inserts, reorgs), v| match v {
electrs_client::Update::AddBlock { .. } => (inserts + 1, reorgs),
electrs_client::Update::RemoveBlock { .. } => (inserts, reorgs + 1),
electrs_client::Update::RemoveCachedBlock { .. } => (inserts, reorgs + 1),
});
println!("Applying new blocks reorgs: {reorgs} new_blocks: {new_blocks}");
println!(
"{:?}",
updates
.iter()
.map(|v| {
match v {
Update::AddBlock { height, hash, .. } => {
println!("{height}: {hash}");
height
}
Update::RemoveBlock { height } => {
println!("{height}: rm");
height
}
Update::RemoveCachedBlock { height, .. } => height,
}
})
.take(30)
.collect_vec()
);
updates.iter().for_each(|i| match i {
Update::AddBlock {
height,
hash,
block,
} => {
dbg!("{}, {}, {:?}", height, hash, block);
}
Update::RemoveBlock { height } => {
panic!("{}", height);
}
Update::RemoveCachedBlock { height, block } => {
panic!("{}, {:?}", height, block);
}
})
}
#[tokio::test]
async fn rest_hash_compare() {
let c = prepare().await;
let last = c.get_last_electrs_block_meta().await.unwrap();
let last2 = c.get_electrs_block_meta(last.height).await.unwrap();
assert!(last == last2);
let prev = [c.get_electrs_block_meta(last.height - 1).await.unwrap()];
let upd = c.fetch_updates::<TestFetched>(&prev).await.unwrap();
let upd = upd
.into_iter()
.map(|v| match v {
Update::AddBlock { height, hash, .. } => (height, hash),
_ => panic!(),
})
.reduce(|acc, v| if v.0 == last.height { v } else { acc })
.unwrap();
assert!(last.block_hash == upd.1)
}
#[tokio::test]
async fn test_limit() {
let mut c = prepare().await;
c.config.limit = Some(5000);
let blocks = c.fetch_updates::<TestFetched>(&[]).await.unwrap();
assert_eq!(blocks.len(), 5000);
c.config.limit = Some(3000);
let blocks = c.fetch_updates::<TestFetched>(&[]).await.unwrap();
assert_eq!(blocks.len(), 3000);
}
#[tokio::test]
async fn fetch_updates_without() {
let c = prepare().await;
let blocks = c.fetch_updates::<TestFetched>(&[]).await.unwrap();
let mut metas = map_blocks(blocks);
let mut start_heights = vec![];
println!(
"first fetch last 30 heights: {:?}",
metas.iter().map(|v| v.height).collect_vec()
);
for i in 0..5 {
let blocks = c.fetch_updates::<TestFetched>(&metas).await.unwrap();
let heights = blocks
.iter()
.map(|v| match v {
Update::AddBlock { height, .. } => height,
_ => panic!("there isn't possible request to delete blocks"),
})
.collect_vec();
println!(
"{i} fetch last 30 heights: {:?}",
heights.iter().rev().take(1).collect_vec()
);
metas = map_blocks(blocks);
start_heights.push(metas.first().map(|v| v.height).unwrap_or(0));
}
start_heights.iter().reduce(|acc, v| {
if acc >= v {
panic!("start heights are not correct: {acc} {v}")
}
v
});
}
fn map_blocks<T>(blocks: Vec<Update<T>>) -> Vec<BlockMeta> {
let metas = blocks
.iter()
.rev()
.take(31)
.rev()
.map(|v| match v {
Update::AddBlock {
height,
hash,
block,
} => (height, hash, block),
_ => panic!("there isn't possible request to delete blocks"),
})
.collect_vec();
let f = metas[0];
let mut prev_hash = f.1;
metas
.into_iter()
.skip(1)
.map(|v| {
let a = BlockMeta {
height: *v.0,
block_hash: *v.1,
prev_block_hash: *prev_hash,
};
prev_hash = v.1;
a
})
.collect_vec()
}
#[tokio::test]
async fn fetch_updates_with_cachefiles() {
let c = prepare().await;
let mut start_heights = vec![];
for i in 0..5 {
let blocks = c.fetch_updates_from_cache::<TestFetched>().await.unwrap();
let metas = blocks_to_metas(&blocks);
for meta in metas.iter() {
c.mark_as_processed(meta.height).await.unwrap();
}
println!(
"{i} fetch first 30 heights: {:?}",
metas.iter().take(30).map(|v| v.height).collect_vec()
);
println!(
"{i} fetch last 30 heights: {:?}",
metas
.iter()
.rev()
.take(30)
.rev()
.map(|v| v.height)
.collect_vec()
);
start_heights.push(metas.first().map(|v| v.height).unwrap_or(0));
}
println!(
"start heights of fetch fetched heights: {:?}",
start_heights.iter().collect_vec()
);
start_heights.iter().reduce(|acc, v| {
if acc >= v {
panic!("start heights are not correct: {acc} {v}")
}
v
});
}
fn blocks_to_metas<T: UpdateCapable>(blocks: &[Update<T>]) -> Vec<BlockMeta> {
blocks
.iter()
.map(|v| match v {
Update::AddBlock { block: b, .. } => BlockMeta {
height: b.get_height(),
block_hash: b.get_hash(),
prev_block_hash: b.get_prev_hash(),
},
_ => panic!("there isn't possible request to delete blocks"),
})
.collect_vec()
}