From: Wei Chen Date: Tue, 10 Sep 2024 15:36:34 +0000 (+0800) Subject: test(chain): Add test for inserting `Header` into `LocalChain` X-Git-Url: http://internal-gitweb-vhost/script/%22https:/database/struct.CommandStringError.html?a=commitdiff_plain;h=7cf4e5b9b3843ae1fce109de611edb0923db63c6;p=bdk test(chain): Add test for inserting `Header` into `LocalChain` --- diff --git a/crates/chain/tests/test_local_chain.rs b/crates/chain/tests/test_local_chain.rs index 94a2498c..7ad03f04 100644 --- a/crates/chain/tests/test_local_chain.rs +++ b/crates/chain/tests/test_local_chain.rs @@ -1,5 +1,6 @@ #![cfg(feature = "miniscript")] +use std::collections::BTreeMap; use std::ops::{Bound, RangeBounds}; use bdk_chain::{ @@ -378,6 +379,101 @@ fn local_chain_insert_block() { } } +#[test] +fn local_chain_insert_header() { + fn header(prev_blockhash: BlockHash) -> Header { + Header { + version: bitcoin::block::Version::default(), + prev_blockhash, + merkle_root: bitcoin::hash_types::TxMerkleNode::all_zeros(), + time: 0, + bits: bitcoin::CompactTarget::default(), + nonce: 0, + } + } + + // Create consecutive headers of height `n`, where the genesis header is height 0. + fn build_headers(n: u32) -> Vec
{ + let mut headers = Vec::new(); + let genesis = header(hash!("_")); + headers.push(genesis); + for i in 1..=n { + let prev = headers[(i - 1) as usize].block_hash(); + headers.push(header(prev)); + } + headers + } + + let headers = build_headers(5); + + fn local_chain(data: Vec<(u32, Header)>) -> LocalChain
{ + bdk_chain::local_chain::LocalChain::from_blocks( + data.into_iter().collect::>(), + ) + .expect("chain must have genesis block") + } + + struct TestCase { + original: LocalChain
, + insert: (u32, Header), + expected_result: Result, AlterCheckPointError>, + expected_final: LocalChain
, + } + + let test_cases = [ + // Test case 1: start with only the genesis header and insert header at height 5. + TestCase { + original: local_chain(vec![(0, headers[0])]), + insert: (5, headers[5]), + expected_result: Ok([(5, Some(headers[5]))].into()), + expected_final: local_chain(vec![(0, headers[0]), (5, headers[5])]), + }, + // Test case 2: start with headers at heights 0 and 3. Insert header at height 4. + TestCase { + original: local_chain(vec![(0, headers[0]), (3, headers[3])]), + insert: (4, headers[4]), + expected_result: Ok([(4, Some(headers[4]))].into()), + expected_final: local_chain(vec![(0, headers[0]), (3, headers[3]), (4, headers[4])]), + }, + // Test case 3: start with headers at heights 0 and 4. Insert header at height 3. + TestCase { + original: local_chain(vec![(0, headers[0]), (4, headers[4])]), + insert: (3, headers[3]), + expected_result: Ok([(3, Some(headers[3]))].into()), + expected_final: local_chain(vec![(0, headers[0]), (3, headers[3]), (4, headers[4])]), + }, + // Test case 4: start with headers at heights 0 and 2. Insert the same header at height 2. + TestCase { + original: local_chain(vec![(0, headers[0]), (2, headers[2])]), + insert: (2, headers[2]), + expected_result: Ok([].into()), + expected_final: local_chain(vec![(0, headers[0]), (2, headers[2])]), + }, + // Test case 5: start with headers at heights 0 and 2. Insert conflicting header at height + // 2. + TestCase { + original: local_chain(vec![(0, headers[0]), (2, headers[2])]), + insert: (2, header(hash!("conflict"))), + expected_result: Err(AlterCheckPointError { + height: 2, + original_hash: headers[2].block_hash(), + update_hash: Some(header(hash!("conflict")).block_hash()), + }), + expected_final: local_chain(vec![(0, headers[0]), (2, headers[2])]), + }, + ]; + + for (i, t) in test_cases.into_iter().enumerate() { + let mut chain = t.original; + assert_eq!( + chain.insert_block(t.insert.0, t.insert.1), + t.expected_result, + "[{i}] unexpected result when inserting block", + ); + assert_eq!(chain, t.expected_final, "[{i}] unexpected final chain",); + } +} + #[test] fn local_chain_disconnect_from() { struct TestCase {