|
1 | 1 | #![cfg(feature = "miniscript")]
|
2 | 2 |
|
| 3 | +use std::collections::BTreeMap; |
3 | 4 | use std::ops::{Bound, RangeBounds};
|
4 | 5 |
|
5 | 6 | use bdk_chain::{
|
@@ -378,6 +379,99 @@ fn local_chain_insert_block() {
|
378 | 379 | }
|
379 | 380 | }
|
380 | 381 |
|
| 382 | +#[test] |
| 383 | +fn local_chain_insert_header() { |
| 384 | + fn header(prev_blockhash: BlockHash) -> Header { |
| 385 | + Header { |
| 386 | + version: bitcoin::block::Version::default(), |
| 387 | + prev_blockhash, |
| 388 | + merkle_root: bitcoin::hash_types::TxMerkleNode::all_zeros(), |
| 389 | + time: 0, |
| 390 | + bits: bitcoin::CompactTarget::default(), |
| 391 | + nonce: 0, |
| 392 | + } |
| 393 | + } |
| 394 | + |
| 395 | + // Create consecutive headers of height `n`, where the genesis header is height 0. |
| 396 | + fn build_headers(n: u32) -> Vec<Header> { |
| 397 | + let mut headers = Vec::new(); |
| 398 | + let genesis = header(hash!("_")); |
| 399 | + headers.push(genesis); |
| 400 | + for i in 1..=n { |
| 401 | + let prev = headers[(i - 1) as usize].block_hash(); |
| 402 | + headers.push(header(prev)); |
| 403 | + } |
| 404 | + headers |
| 405 | + } |
| 406 | + |
| 407 | + let headers = build_headers(5); |
| 408 | + |
| 409 | + fn local_chain(data: Vec<(u32, Header)>) -> LocalChain<Header> { |
| 410 | + bdk_chain::local_chain::LocalChain::from_data(data.into_iter().collect::<BTreeMap<_, _>>()) |
| 411 | + .expect("chain must have genesis block") |
| 412 | + } |
| 413 | + |
| 414 | + struct TestCase { |
| 415 | + original: LocalChain<Header>, |
| 416 | + insert: (u32, Header), |
| 417 | + expected_result: Result<ChangeSet<Header>, AlterCheckPointError>, |
| 418 | + expected_final: LocalChain<Header>, |
| 419 | + } |
| 420 | + |
| 421 | + let test_cases = [ |
| 422 | + // Test case 1: start with only the genesis header and insert header at height 5. |
| 423 | + TestCase { |
| 424 | + original: local_chain(vec![(0, headers[0])]), |
| 425 | + insert: (5, headers[5]), |
| 426 | + expected_result: Ok([(5, Some(headers[5]))].into()), |
| 427 | + expected_final: local_chain(vec![(0, headers[0]), (5, headers[5])]), |
| 428 | + }, |
| 429 | + // Test case 2: start with headers at heights 0 and 3. Insert header at height 4. |
| 430 | + TestCase { |
| 431 | + original: local_chain(vec![(0, headers[0]), (3, headers[3])]), |
| 432 | + insert: (4, headers[4]), |
| 433 | + expected_result: Ok([(4, Some(headers[4]))].into()), |
| 434 | + expected_final: local_chain(vec![(0, headers[0]), (3, headers[3]), (4, headers[4])]), |
| 435 | + }, |
| 436 | + // Test case 3: start with headers at heights 0 and 4. Insert header at height 3. |
| 437 | + TestCase { |
| 438 | + original: local_chain(vec![(0, headers[0]), (4, headers[4])]), |
| 439 | + insert: (3, headers[3]), |
| 440 | + expected_result: Ok([(3, Some(headers[3]))].into()), |
| 441 | + expected_final: local_chain(vec![(0, headers[0]), (3, headers[3]), (4, headers[4])]), |
| 442 | + }, |
| 443 | + // Test case 4: start with headers at heights 0 and 2. Insert the same header at height 2. |
| 444 | + TestCase { |
| 445 | + original: local_chain(vec![(0, headers[0]), (2, headers[2])]), |
| 446 | + insert: (2, headers[2]), |
| 447 | + expected_result: Ok([].into()), |
| 448 | + expected_final: local_chain(vec![(0, headers[0]), (2, headers[2])]), |
| 449 | + }, |
| 450 | + // Test case 5: start with headers at heights 0 and 2. Insert conflicting header at height 2. |
| 451 | + TestCase { |
| 452 | + original: local_chain(vec![(0, headers[0]), (2, headers[2])]), |
| 453 | + insert: (2, header(hash!("conflict"))), |
| 454 | + expected_result: Err(AlterCheckPointError { |
| 455 | + height: 2, |
| 456 | + original_hash: headers[2].block_hash(), |
| 457 | + update_hash: Some(header(hash!("conflict")).block_hash()), |
| 458 | + }), |
| 459 | + expected_final: local_chain(vec![(0, headers[0]), (2, headers[2])]), |
| 460 | + }, |
| 461 | + ]; |
| 462 | + |
| 463 | + for (i, t) in test_cases.into_iter().enumerate() { |
| 464 | + let mut chain = t.original; |
| 465 | + assert_eq!( |
| 466 | + chain.insert_data(t.insert.0, t.insert.1), |
| 467 | + t.expected_result, |
| 468 | + "[{}] unexpected result when inserting block", |
| 469 | + i, |
| 470 | + ); |
| 471 | + assert_eq!(chain, t.expected_final, "[{}] unexpected final chain", i,); |
| 472 | + } |
| 473 | +} |
| 474 | + |
381 | 475 | #[test]
|
382 | 476 | fn local_chain_disconnect_from() {
|
383 | 477 | struct TestCase {
|
|
0 commit comments