]> Untitled Git - bdk/commitdiff
test(chain): Add test for inserting `Header` into `LocalChain`
authorWei Chen <wzc110@gmail.com>
Tue, 10 Sep 2024 15:36:34 +0000 (23:36 +0800)
committer志宇 <hello@evanlinjin.me>
Sun, 14 Sep 2025 23:20:01 +0000 (23:20 +0000)
crates/chain/tests/test_local_chain.rs

index 94a2498c1c20ea1942f4071be740c43e6fb578c1..7ad03f04f53a05b3d3416310628bb18f29d18cfc 100644 (file)
@@ -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<Header> {
+        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<Header> {
+        bdk_chain::local_chain::LocalChain::from_blocks(
+            data.into_iter().collect::<BTreeMap<_, _>>(),
+        )
+        .expect("chain must have genesis block")
+    }
+
+    struct TestCase {
+        original: LocalChain<Header>,
+        insert: (u32, Header),
+        expected_result: Result<ChangeSet<Header>, AlterCheckPointError>,
+        expected_final: LocalChain<Header>,
+    }
+
+    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 {