},
BlockId,
};
+use bdk_testenv::{chain_update, hash, local_chain};
use bitcoin::{block::Header, hashes::Hash, BlockHash};
use proptest::prelude::*;
-#[macro_use]
-mod common;
-
#[derive(Debug)]
struct TestLocalChain<'a> {
name: &'static str,
[
TestLocalChain {
name: "add first tip",
- chain: local_chain![(0, h!("A"))],
- update: chain_update![(0, h!("A"))],
+ chain: local_chain![(0, hash!("A"))],
+ update: chain_update![(0, hash!("A"))],
exp: ExpectedResult::Ok {
changeset: &[],
- init_changeset: &[(0, Some(h!("A")))],
+ init_changeset: &[(0, Some(hash!("A")))],
},
},
TestLocalChain {
name: "add second tip",
- chain: local_chain![(0, h!("A"))],
- update: chain_update![(0, h!("A")), (1, h!("B"))],
+ chain: local_chain![(0, hash!("A"))],
+ update: chain_update![(0, hash!("A")), (1, hash!("B"))],
exp: ExpectedResult::Ok {
- changeset: &[(1, Some(h!("B")))],
- init_changeset: &[(0, Some(h!("A"))), (1, Some(h!("B")))],
+ changeset: &[(1, Some(hash!("B")))],
+ init_changeset: &[(0, Some(hash!("A"))), (1, Some(hash!("B")))],
},
},
TestLocalChain {
name: "two disjoint chains cannot merge",
- chain: local_chain![(0, h!("_")), (1, h!("A"))],
- update: chain_update![(0, h!("_")), (2, h!("B"))],
+ chain: local_chain![(0, hash!("_")), (1, hash!("A"))],
+ update: chain_update![(0, hash!("_")), (2, hash!("B"))],
exp: ExpectedResult::Err(CannotConnectError {
try_include_height: 1,
}),
},
TestLocalChain {
name: "two disjoint chains cannot merge (existing chain longer)",
- chain: local_chain![(0, h!("_")), (2, h!("A"))],
- update: chain_update![(0, h!("_")), (1, h!("B"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("A"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("B"))],
exp: ExpectedResult::Err(CannotConnectError {
try_include_height: 2,
}),
},
TestLocalChain {
name: "duplicate chains should merge",
- chain: local_chain![(0, h!("A"))],
- update: chain_update![(0, h!("A"))],
+ chain: local_chain![(0, hash!("A"))],
+ update: chain_update![(0, hash!("A"))],
exp: ExpectedResult::Ok {
changeset: &[],
- init_changeset: &[(0, Some(h!("A")))],
+ init_changeset: &[(0, Some(hash!("A")))],
},
},
// Introduce an older checkpoint (B)
// update | _ B C
TestLocalChain {
name: "can introduce older checkpoint",
- chain: local_chain![(0, h!("_")), (2, h!("C")), (3, h!("D"))],
- update: chain_update![(0, h!("_")), (1, h!("B")), (2, h!("C"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("C")), (3, hash!("D"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("B")), (2, hash!("C"))],
exp: ExpectedResult::Ok {
- changeset: &[(1, Some(h!("B")))],
- init_changeset: &[(0, Some(h!("_"))), (1, Some(h!("B"))), (2, Some(h!("C"))), (3, Some(h!("D")))],
+ changeset: &[(1, Some(hash!("B")))],
+ init_changeset: &[(0, Some(hash!("_"))), (1, Some(hash!("B"))), (2, Some(hash!("C"))), (3, Some(hash!("D")))],
},
},
// Introduce an older checkpoint (A) that is not directly behind PoA
// update | _ A C
TestLocalChain {
name: "can introduce older checkpoint 2",
- chain: local_chain![(0, h!("_")), (3, h!("B")), (4, h!("C"))],
- update: chain_update![(0, h!("_")), (2, h!("A")), (4, h!("C"))],
+ chain: local_chain![(0, hash!("_")), (3, hash!("B")), (4, hash!("C"))],
+ update: chain_update![(0, hash!("_")), (2, hash!("A")), (4, hash!("C"))],
exp: ExpectedResult::Ok {
- changeset: &[(2, Some(h!("A")))],
- init_changeset: &[(0, Some(h!("_"))), (2, Some(h!("A"))), (3, Some(h!("B"))), (4, Some(h!("C")))],
+ changeset: &[(2, Some(hash!("A")))],
+ init_changeset: &[(0, Some(hash!("_"))), (2, Some(hash!("A"))), (3, Some(hash!("B"))), (4, Some(hash!("C")))],
}
},
// Introduce an older checkpoint (B) that is not the oldest checkpoint
// update | _ B C
TestLocalChain {
name: "can introduce older checkpoint 3",
- chain: local_chain![(0, h!("_")), (1, h!("A")), (3, h!("C"))],
- update: chain_update![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
+ chain: local_chain![(0, hash!("_")), (1, hash!("A")), (3, hash!("C"))],
+ update: chain_update![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
exp: ExpectedResult::Ok {
- changeset: &[(2, Some(h!("B")))],
- init_changeset: &[(0, Some(h!("_"))), (1, Some(h!("A"))), (2, Some(h!("B"))), (3, Some(h!("C")))],
+ changeset: &[(2, Some(hash!("B")))],
+ init_changeset: &[(0, Some(hash!("_"))), (1, Some(hash!("A"))), (2, Some(hash!("B"))), (3, Some(hash!("C")))],
}
},
// Introduce two older checkpoints below the PoA
// update | _ A B C
TestLocalChain {
name: "introduce two older checkpoints below PoA",
- chain: local_chain![(0, h!("_")), (3, h!("C"))],
- update: chain_update![(0, h!("_")), (1, h!("A")), (2, h!("B")), (3, h!("C"))],
+ chain: local_chain![(0, hash!("_")), (3, hash!("C"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("A")), (2, hash!("B")), (3, hash!("C"))],
exp: ExpectedResult::Ok {
- changeset: &[(1, Some(h!("A"))), (2, Some(h!("B")))],
- init_changeset: &[(0, Some(h!("_"))), (1, Some(h!("A"))), (2, Some(h!("B"))), (3, Some(h!("C")))],
+ changeset: &[(1, Some(hash!("A"))), (2, Some(hash!("B")))],
+ init_changeset: &[(0, Some(hash!("_"))), (1, Some(hash!("A"))), (2, Some(hash!("B"))), (3, Some(hash!("C")))],
},
},
TestLocalChain {
name: "fix blockhash before agreement point",
- chain: local_chain![(0, h!("im-wrong")), (1, h!("we-agree"))],
- update: chain_update![(0, h!("fix")), (1, h!("we-agree"))],
+ chain: local_chain![(0, hash!("im-wrong")), (1, hash!("we-agree"))],
+ update: chain_update![(0, hash!("fix")), (1, hash!("we-agree"))],
exp: ExpectedResult::Ok {
- changeset: &[(0, Some(h!("fix")))],
- init_changeset: &[(0, Some(h!("fix"))), (1, Some(h!("we-agree")))],
+ changeset: &[(0, Some(hash!("fix")))],
+ init_changeset: &[(0, Some(hash!("fix"))), (1, Some(hash!("we-agree")))],
},
},
// B and C are in both chain and update
// This should succeed with the point of agreement being C and A should be added in addition.
TestLocalChain {
name: "two points of agreement",
- chain: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
- update: chain_update![(0, h!("_")), (1, h!("A")), (2, h!("B")), (3, h!("C")), (4, h!("D"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("A")), (2, hash!("B")), (3, hash!("C")), (4, hash!("D"))],
exp: ExpectedResult::Ok {
- changeset: &[(1, Some(h!("A"))), (4, Some(h!("D")))],
+ changeset: &[(1, Some(hash!("A"))), (4, Some(hash!("D")))],
init_changeset: &[
- (0, Some(h!("_"))),
- (1, Some(h!("A"))),
- (2, Some(h!("B"))),
- (3, Some(h!("C"))),
- (4, Some(h!("D"))),
+ (0, Some(hash!("_"))),
+ (1, Some(hash!("A"))),
+ (2, Some(hash!("B"))),
+ (3, Some(hash!("C"))),
+ (4, Some(hash!("D"))),
],
},
},
// This should fail as we cannot figure out whether C & D are on the same chain
TestLocalChain {
name: "update and chain does not connect",
- chain: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
- update: chain_update![(0, h!("_")), (1, h!("A")), (2, h!("B")), (4, h!("D"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("A")), (2, hash!("B")), (4, hash!("D"))],
exp: ExpectedResult::Err(CannotConnectError {
try_include_height: 3,
}),
// This should succeed and invalidate B,C and E with point of agreement being A.
TestLocalChain {
name: "transitive invalidation applies to checkpoints higher than invalidation",
- chain: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C")), (5, h!("E"))],
- update: chain_update![(0, h!("_")), (2, h!("B'")), (3, h!("C'")), (4, h!("D"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C")), (5, hash!("E"))],
+ update: chain_update![(0, hash!("_")), (2, hash!("B'")), (3, hash!("C'")), (4, hash!("D"))],
exp: ExpectedResult::Ok {
changeset: &[
- (2, Some(h!("B'"))),
- (3, Some(h!("C'"))),
- (4, Some(h!("D"))),
+ (2, Some(hash!("B'"))),
+ (3, Some(hash!("C'"))),
+ (4, Some(hash!("D"))),
(5, None),
],
init_changeset: &[
- (0, Some(h!("_"))),
- (2, Some(h!("B'"))),
- (3, Some(h!("C'"))),
- (4, Some(h!("D"))),
+ (0, Some(hash!("_"))),
+ (2, Some(hash!("B'"))),
+ (3, Some(hash!("C'"))),
+ (4, Some(hash!("D"))),
],
},
},
// This should succeed and invalidate B, C and E with no point of agreement
TestLocalChain {
name: "transitive invalidation applies to checkpoints higher than invalidation no point of agreement",
- chain: local_chain![(0, h!("_")), (1, h!("B")), (2, h!("C")), (4, h!("E"))],
- update: chain_update![(0, h!("_")), (1, h!("B'")), (2, h!("C'")), (3, h!("D"))],
+ chain: local_chain![(0, hash!("_")), (1, hash!("B")), (2, hash!("C")), (4, hash!("E"))],
+ update: chain_update![(0, hash!("_")), (1, hash!("B'")), (2, hash!("C'")), (3, hash!("D"))],
exp: ExpectedResult::Ok {
changeset: &[
- (1, Some(h!("B'"))),
- (2, Some(h!("C'"))),
- (3, Some(h!("D"))),
+ (1, Some(hash!("B'"))),
+ (2, Some(hash!("C'"))),
+ (3, Some(hash!("D"))),
(4, None)
],
init_changeset: &[
- (0, Some(h!("_"))),
- (1, Some(h!("B'"))),
- (2, Some(h!("C'"))),
- (3, Some(h!("D"))),
+ (0, Some(hash!("_"))),
+ (1, Some(hash!("B'"))),
+ (2, Some(hash!("C'"))),
+ (3, Some(hash!("D"))),
],
},
},
// A was invalid.
TestLocalChain {
name: "invalidation but no connection",
- chain: local_chain![(0, h!("_")), (1, h!("A")), (2, h!("B")), (3, h!("C")), (5, h!("E"))],
- update: chain_update![(0, h!("_")), (2, h!("B'")), (3, h!("C'")), (4, h!("D"))],
+ chain: local_chain![(0, hash!("_")), (1, hash!("A")), (2, hash!("B")), (3, hash!("C")), (5, hash!("E"))],
+ update: chain_update![(0, hash!("_")), (2, hash!("B'")), (3, hash!("C'")), (4, hash!("D"))],
exp: ExpectedResult::Err(CannotConnectError { try_include_height: 1 }),
},
// Introduce blocks between two points of agreement
// update | A C E F
TestLocalChain {
name: "introduce blocks between two points of agreement",
- chain: local_chain![(0, h!("A")), (1, h!("B")), (3, h!("D")), (4, h!("E"))],
- update: chain_update![(0, h!("A")), (2, h!("C")), (4, h!("E")), (5, h!("F"))],
+ chain: local_chain![(0, hash!("A")), (1, hash!("B")), (3, hash!("D")), (4, hash!("E"))],
+ update: chain_update![(0, hash!("A")), (2, hash!("C")), (4, hash!("E")), (5, hash!("F"))],
exp: ExpectedResult::Ok {
changeset: &[
- (2, Some(h!("C"))),
- (5, Some(h!("F"))),
+ (2, Some(hash!("C"))),
+ (5, Some(hash!("F"))),
],
init_changeset: &[
- (0, Some(h!("A"))),
- (1, Some(h!("B"))),
- (2, Some(h!("C"))),
- (3, Some(h!("D"))),
- (4, Some(h!("E"))),
- (5, Some(h!("F"))),
+ (0, Some(hash!("A"))),
+ (1, Some(hash!("B"))),
+ (2, Some(hash!("C"))),
+ (3, Some(hash!("D"))),
+ (4, Some(hash!("E"))),
+ (5, Some(hash!("F"))),
],
},
},
// update | A C D'
TestLocalChain {
name: "allow update that is shorter than original chain",
- chain: local_chain![(0, h!("_")), (2, h!("C")), (3, h!("D")), (4, h!("E")), (5, h!("F"))],
- update: chain_update![(0, h!("_")), (2, h!("C")), (3, h!("D'"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("C")), (3, hash!("D")), (4, hash!("E")), (5, hash!("F"))],
+ update: chain_update![(0, hash!("_")), (2, hash!("C")), (3, hash!("D'"))],
exp: ExpectedResult::Ok {
changeset: &[
- (3, Some(h!("D'"))),
+ (3, Some(hash!("D'"))),
(4, None),
(5, None),
],
init_changeset: &[
- (0, Some(h!("_"))),
- (2, Some(h!("C"))),
- (3, Some(h!("D'"))),
+ (0, Some(hash!("_"))),
+ (2, Some(hash!("C"))),
+ (3, Some(hash!("D'"))),
],
},
},
let test_cases = [
TestCase {
- original: local_chain![(0, h!("_"))],
- insert: (5, h!("block5")),
- expected_result: Ok([(5, Some(h!("block5")))].into()),
- expected_final: local_chain![(0, h!("_")), (5, h!("block5"))],
+ original: local_chain![(0, hash!("_"))],
+ insert: (5, hash!("block5")),
+ expected_result: Ok([(5, Some(hash!("block5")))].into()),
+ expected_final: local_chain![(0, hash!("_")), (5, hash!("block5"))],
},
TestCase {
- original: local_chain![(0, h!("_")), (3, h!("A"))],
- insert: (4, h!("B")),
- expected_result: Ok([(4, Some(h!("B")))].into()),
- expected_final: local_chain![(0, h!("_")), (3, h!("A")), (4, h!("B"))],
+ original: local_chain![(0, hash!("_")), (3, hash!("A"))],
+ insert: (4, hash!("B")),
+ expected_result: Ok([(4, Some(hash!("B")))].into()),
+ expected_final: local_chain![(0, hash!("_")), (3, hash!("A")), (4, hash!("B"))],
},
TestCase {
- original: local_chain![(0, h!("_")), (4, h!("B"))],
- insert: (3, h!("A")),
- expected_result: Ok([(3, Some(h!("A")))].into()),
- expected_final: local_chain![(0, h!("_")), (3, h!("A")), (4, h!("B"))],
+ original: local_chain![(0, hash!("_")), (4, hash!("B"))],
+ insert: (3, hash!("A")),
+ expected_result: Ok([(3, Some(hash!("A")))].into()),
+ expected_final: local_chain![(0, hash!("_")), (3, hash!("A")), (4, hash!("B"))],
},
TestCase {
- original: local_chain![(0, h!("_")), (2, h!("K"))],
- insert: (2, h!("K")),
+ original: local_chain![(0, hash!("_")), (2, hash!("K"))],
+ insert: (2, hash!("K")),
expected_result: Ok([].into()),
- expected_final: local_chain![(0, h!("_")), (2, h!("K"))],
+ expected_final: local_chain![(0, hash!("_")), (2, hash!("K"))],
},
TestCase {
- original: local_chain![(0, h!("_")), (2, h!("K"))],
- insert: (2, h!("J")),
+ original: local_chain![(0, hash!("_")), (2, hash!("K"))],
+ insert: (2, hash!("J")),
expected_result: Err(AlterCheckPointError {
height: 2,
- original_hash: h!("K"),
- update_hash: Some(h!("J")),
+ original_hash: hash!("K"),
+ update_hash: Some(hash!("J")),
}),
- expected_final: local_chain![(0, h!("_")), (2, h!("K"))],
+ expected_final: local_chain![(0, hash!("_")), (2, hash!("K"))],
},
];
let test_cases = [
TestCase {
name: "try_replace_genesis_should_fail",
- original: local_chain![(0, h!("_"))],
- disconnect_from: (0, h!("_")),
+ original: local_chain![(0, hash!("_"))],
+ disconnect_from: (0, hash!("_")),
exp_result: Err(MissingGenesisError),
- exp_final: local_chain![(0, h!("_"))],
+ exp_final: local_chain![(0, hash!("_"))],
},
TestCase {
name: "try_replace_genesis_should_fail_2",
- original: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
- disconnect_from: (0, h!("_")),
+ original: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
+ disconnect_from: (0, hash!("_")),
exp_result: Err(MissingGenesisError),
- exp_final: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
+ exp_final: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
},
TestCase {
name: "from_does_not_exist",
- original: local_chain![(0, h!("_")), (3, h!("C"))],
- disconnect_from: (2, h!("B")),
+ original: local_chain![(0, hash!("_")), (3, hash!("C"))],
+ disconnect_from: (2, hash!("B")),
exp_result: Ok(ChangeSet::default()),
- exp_final: local_chain![(0, h!("_")), (3, h!("C"))],
+ exp_final: local_chain![(0, hash!("_")), (3, hash!("C"))],
},
TestCase {
name: "from_has_different_blockhash",
- original: local_chain![(0, h!("_")), (2, h!("B"))],
- disconnect_from: (2, h!("not_B")),
+ original: local_chain![(0, hash!("_")), (2, hash!("B"))],
+ disconnect_from: (2, hash!("not_B")),
exp_result: Ok(ChangeSet::default()),
- exp_final: local_chain![(0, h!("_")), (2, h!("B"))],
+ exp_final: local_chain![(0, hash!("_")), (2, hash!("B"))],
},
TestCase {
name: "disconnect_one",
- original: local_chain![(0, h!("_")), (2, h!("B"))],
- disconnect_from: (2, h!("B")),
+ original: local_chain![(0, hash!("_")), (2, hash!("B"))],
+ disconnect_from: (2, hash!("B")),
exp_result: Ok(ChangeSet::from_iter([(2, None)])),
- exp_final: local_chain![(0, h!("_"))],
+ exp_final: local_chain![(0, hash!("_"))],
},
TestCase {
name: "disconnect_three",
- original: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C")), (4, h!("D"))],
- disconnect_from: (2, h!("B")),
+ original: local_chain![
+ (0, hash!("_")),
+ (2, hash!("B")),
+ (3, hash!("C")),
+ (4, hash!("D"))
+ ],
+ disconnect_from: (2, hash!("B")),
exp_result: Ok(ChangeSet::from_iter([(2, None), (3, None), (4, None)])),
- exp_final: local_chain![(0, h!("_"))],
+ exp_final: local_chain![(0, hash!("_"))],
},
];
let test_cases = [
TestCase {
name: "in_order",
- blocks: &[(0, h!("A")), (1, h!("B")), (3, h!("D"))],
+ blocks: &[(0, hash!("A")), (1, hash!("B")), (3, hash!("D"))],
exp_result: Ok(()),
},
TestCase {
name: "with_duplicates",
- blocks: &[(1, h!("B")), (2, h!("C")), (2, h!("C'"))],
- exp_result: Err(Some((2, h!("C")))),
+ blocks: &[(1, hash!("B")), (2, hash!("C")), (2, hash!("C'"))],
+ exp_result: Err(Some((2, hash!("C")))),
},
TestCase {
name: "not_in_order",
- blocks: &[(1, h!("B")), (3, h!("D")), (2, h!("C"))],
- exp_result: Err(Some((3, h!("D")))),
+ blocks: &[(1, hash!("B")), (3, hash!("D")), (2, hash!("C"))],
+ exp_result: Err(Some((3, hash!("D")))),
},
TestCase {
name: "empty",
},
TestCase {
name: "single",
- blocks: &[(21, h!("million"))],
+ blocks: &[(21, hash!("million"))],
exp_result: Ok(()),
},
];
let test_cases = [
TestCase {
- chain: local_chain![(0, h!("_")), (1, h!("A"))],
+ chain: local_chain![(0, hash!("_")), (1, hash!("A"))],
query_range: (0, 2),
},
TestCase {
- chain: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
query_range: (0, 3),
},
];
let test_cases = [
TestCase {
name: "insert_above_tip",
- chain: &[(1, h!("a")), (2, h!("b"))],
- to_insert: (4, h!("d")),
- exp_final_chain: &[(1, h!("a")), (2, h!("b")), (4, h!("d"))],
+ chain: &[(1, hash!("a")), (2, hash!("b"))],
+ to_insert: (4, hash!("d")),
+ exp_final_chain: &[(1, hash!("a")), (2, hash!("b")), (4, hash!("d"))],
},
TestCase {
name: "insert_already_exists_expect_no_change",
- chain: &[(1, h!("a")), (2, h!("b")), (3, h!("c"))],
- to_insert: (2, h!("b")),
- exp_final_chain: &[(1, h!("a")), (2, h!("b")), (3, h!("c"))],
+ chain: &[(1, hash!("a")), (2, hash!("b")), (3, hash!("c"))],
+ to_insert: (2, hash!("b")),
+ exp_final_chain: &[(1, hash!("a")), (2, hash!("b")), (3, hash!("c"))],
},
TestCase {
name: "insert_in_middle",
- chain: &[(2, h!("b")), (4, h!("d")), (5, h!("e"))],
- to_insert: (3, h!("c")),
- exp_final_chain: &[(2, h!("b")), (3, h!("c")), (4, h!("d")), (5, h!("e"))],
+ chain: &[(2, hash!("b")), (4, hash!("d")), (5, hash!("e"))],
+ to_insert: (3, hash!("c")),
+ exp_final_chain: &[
+ (2, hash!("b")),
+ (3, hash!("c")),
+ (4, hash!("d")),
+ (5, hash!("e")),
+ ],
},
TestCase {
name: "replace_one",
- chain: &[(3, h!("c")), (4, h!("d")), (5, h!("e"))],
- to_insert: (5, h!("E")),
- exp_final_chain: &[(3, h!("c")), (4, h!("d")), (5, h!("E"))],
+ chain: &[(3, hash!("c")), (4, hash!("d")), (5, hash!("e"))],
+ to_insert: (5, hash!("E")),
+ exp_final_chain: &[(3, hash!("c")), (4, hash!("d")), (5, hash!("E"))],
},
TestCase {
name: "insert_conflict_should_evict",
- chain: &[(3, h!("c")), (4, h!("d")), (5, h!("e")), (6, h!("f"))],
- to_insert: (4, h!("D")),
- exp_final_chain: &[(3, h!("c")), (4, h!("D"))],
+ chain: &[
+ (3, hash!("c")),
+ (4, hash!("d")),
+ (5, hash!("e")),
+ (6, hash!("f")),
+ ],
+ to_insert: (4, hash!("D")),
+ exp_final_chain: &[(3, hash!("c")), (4, hash!("D"))],
},
];
fn genesis_block() -> impl Iterator<Item = BlockId> {
- core::iter::once((0, h!("_"))).map(BlockId::from)
+ core::iter::once((0, hash!("_"))).map(BlockId::from)
}
for t in test_cases.into_iter() {
let test_cases = [
{
- let header = header_from_prev_blockhash(h!("_"));
+ let header = header_from_prev_blockhash(hash!("_"));
let hash = header.block_hash();
let height = 1;
let connected_to = BlockId { height, hash };
TestCase {
name: "connected_to_self_header_applied_to_self",
- chain: local_chain![(0, h!("_")), (height, hash)],
+ chain: local_chain![(0, hash!("_")), (height, hash)],
header,
height,
connected_to,
}
},
{
- let prev_hash = h!("A");
+ let prev_hash = hash!("A");
let prev_height = 1;
let header = header_from_prev_blockhash(prev_hash);
let hash = header.block_hash();
};
TestCase {
name: "connected_to_prev_header_applied_to_self",
- chain: local_chain![(0, h!("_")), (prev_height, prev_hash)],
+ chain: local_chain![(0, hash!("_")), (prev_height, prev_hash)],
header,
height,
connected_to,
}
},
{
- let header = header_from_prev_blockhash(h!("Z"));
+ let header = header_from_prev_blockhash(hash!("Z"));
let height = 10;
let hash = header.block_hash();
let prev_height = height - 1;
let prev_hash = header.prev_blockhash;
TestCase {
name: "connect_at_connected_to",
- chain: local_chain![(0, h!("_")), (2, h!("B")), (3, h!("C"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("B")), (3, hash!("C"))],
header,
height: 10,
connected_to: BlockId {
height: 3,
- hash: h!("C"),
+ hash: hash!("C"),
},
exp_result: Ok(vec![(prev_height, Some(prev_hash)), (height, Some(hash))]),
}
},
{
- let prev_hash = h!("A");
+ let prev_hash = hash!("A");
let prev_height = 1;
let header = header_from_prev_blockhash(prev_hash);
let connected_to = BlockId {
height: prev_height,
- hash: h!("not_prev_hash"),
+ hash: hash!("not_prev_hash"),
};
TestCase {
name: "inconsistent_prev_hash",
- chain: local_chain![(0, h!("_")), (prev_height, h!("not_prev_hash"))],
+ chain: local_chain![(0, hash!("_")), (prev_height, hash!("not_prev_hash"))],
header,
height: prev_height + 1,
connected_to,
}
},
{
- let prev_hash = h!("A");
+ let prev_hash = hash!("A");
let prev_height = 1;
let header = header_from_prev_blockhash(prev_hash);
let height = prev_height + 1;
let connected_to = BlockId {
height,
- hash: h!("not_current_hash"),
+ hash: hash!("not_current_hash"),
};
TestCase {
name: "inconsistent_current_block",
- chain: local_chain![(0, h!("_")), (height, h!("not_current_hash"))],
+ chain: local_chain![(0, hash!("_")), (height, hash!("not_current_hash"))],
header,
height,
connected_to,
}
},
{
- let header = header_from_prev_blockhash(h!("B"));
+ let header = header_from_prev_blockhash(hash!("B"));
let height = 3;
let connected_to = BlockId {
height: 4,
- hash: h!("D"),
+ hash: hash!("D"),
};
TestCase {
name: "connected_to_is_greater",
- chain: local_chain![(0, h!("_")), (2, h!("B"))],
+ chain: local_chain![(0, hash!("_")), (2, hash!("B"))],
header,
height,
connected_to,
tx_graph::{ChangeSet, TxGraph},
Anchor, ChainOracle, ChainPosition, Merge,
};
+use bdk_testenv::{block_id, hash, utils::new_tx};
use bitcoin::{
absolute, hashes::Hash, transaction, Amount, BlockHash, OutPoint, ScriptBuf, SignedAmount,
Transaction, TxIn, TxOut, Txid,
// 2 (Outpoint, TxOut) tuples that denotes original data in the graph, as partial transactions.
let original_ops = [
(
- OutPoint::new(h!("tx1"), 1),
+ OutPoint::new(hash!("tx1"), 1),
TxOut {
value: Amount::from_sat(10_000),
script_pubkey: ScriptBuf::new(),
},
),
(
- OutPoint::new(h!("tx1"), 2),
+ OutPoint::new(hash!("tx1"), 2),
TxOut {
value: Amount::from_sat(20_000),
script_pubkey: ScriptBuf::new(),
// Another (OutPoint, TxOut) tuple to be used as update as partial transaction.
let update_ops = [(
- OutPoint::new(h!("tx2"), 0),
+ OutPoint::new(hash!("tx2"), 0),
TxOut {
value: Amount::from_sat(20_000),
script_pubkey: ScriptBuf::new(),
// Conf anchor used to mark the full transaction as confirmed.
let conf_anchor = BlockId {
height: 100,
- hash: h!("random blockhash"),
+ hash: hash!("random blockhash"),
};
// Unconfirmed seen_at timestamp to mark the partial transactions as unconfirmed.
txs: [Arc::new(update_tx.clone())].into(),
txouts: update_ops.clone().into(),
anchors: [(conf_anchor, update_tx.compute_txid()),].into(),
- last_seen: [(h!("tx2"), 1000000)].into()
+ last_seen: [(hash!("tx2"), 1000000)].into()
}
);
// Check TxOuts are fetched correctly from the graph.
assert_eq!(
- graph.tx_outputs(h!("tx1")).expect("should exists"),
+ graph.tx_outputs(hash!("tx1")).expect("should exists"),
[
(
1u32,
txs: [Arc::new(update_tx.clone())].into(),
txouts: update_ops.into_iter().chain(original_ops).collect(),
anchors: [(conf_anchor, update_tx.compute_txid()),].into(),
- last_seen: [(h!("tx2"), 1000000)].into()
+ last_seen: [(hash!("tx2"), 1000000)].into()
}
);
}
let intxout1 = (
OutPoint {
- txid: h!("dangling output"),
+ txid: hash!("dangling output"),
vout: 0,
},
TxOut {
// If we have an unknown outpoint, fee should return CalculateFeeError::MissingTxOut.
let outpoint = OutPoint {
- txid: h!("unknown_txid"),
+ txid: hash!("unknown_txid"),
vout: 0,
};
tx.input.push(TxIn {
let tx_a0 = Transaction {
input: vec![TxIn {
- previous_output: OutPoint::new(h!("op0"), 0),
+ previous_output: OutPoint::new(hash!("op0"), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL, TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_b0 spends tx_a0
..TxIn::default()
}],
output: vec![TxOut::NULL, TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_b1 spends tx_a0
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
let tx_b2 = Transaction {
input: vec![TxIn {
- previous_output: OutPoint::new(h!("op1"), 0),
+ previous_output: OutPoint::new(hash!("op1"), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_c0 spends tx_b0
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_c1 spends tx_b0
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_c2 spends tx_b1 and tx_b2
},
],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
let tx_c3 = Transaction {
input: vec![TxIn {
- previous_output: OutPoint::new(h!("op2"), 0),
+ previous_output: OutPoint::new(hash!("op2"), 0),
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_d0 spends tx_c1
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_d1 spends tx_c2 and tx_c3
},
],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_e0 spends tx_d1
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
let mut graph = TxGraph::<BlockId>::new([
#[test]
fn test_conflicting_descendants() {
- let previous_output = OutPoint::new(h!("op"), 2);
+ let previous_output = OutPoint::new(hash!("op"), 2);
// tx_a spends previous_output
let tx_a = Transaction {
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// tx_a2 spends previous_output and conflicts with tx_a
..TxIn::default()
}],
output: vec![TxOut::NULL, TxOut::NULL],
- ..common::new_tx(1)
+ ..new_tx(1)
};
// tx_b spends tx_a
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(2)
+ ..new_tx(2)
};
let txid_a = tx_a.compute_txid();
fn test_descendants_no_repeat() {
let tx_a = Transaction {
output: vec![TxOut::NULL, TxOut::NULL, TxOut::NULL],
- ..common::new_tx(0)
+ ..new_tx(0)
};
let txs_b = (0..3)
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(1)
+ ..new_tx(1)
})
.collect::<Vec<_>>();
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(2)
+ ..new_tx(2)
})
.collect::<Vec<_>>();
},
],
output: vec![TxOut::NULL],
- ..common::new_tx(3)
+ ..new_tx(3)
};
let tx_e = Transaction {
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(4)
+ ..new_tx(4)
};
let txs_not_connected = (10..20)
.map(|v| Transaction {
input: vec![TxIn {
- previous_output: OutPoint::new(h!("tx_does_not_exist"), v),
+ previous_output: OutPoint::new(hash!("tx_does_not_exist"), v),
..TxIn::default()
}],
output: vec![TxOut::NULL],
- ..common::new_tx(v)
+ ..new_tx(v)
})
.collect::<Vec<_>>();
script_pubkey: ScriptBuf::new(),
},
],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// The first confirmed transaction spends vout: 0. And is confirmed at block 98.
script_pubkey: ScriptBuf::new(),
},
],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// The second transactions spends vout:1, and is unconfirmed.
script_pubkey: ScriptBuf::new(),
},
],
- ..common::new_tx(0)
+ ..new_tx(0)
};
let mut graph = TxGraph::<ConfirmationBlockTime>::default();
previous_output: OutPoint::new(tx_0.compute_txid(), 0),
..Default::default()
}],
- ..common::new_tx(0)
+ ..new_tx(0)
};
let _ = graph.insert_tx(tx_1_conflict.clone());
previous_output: OutPoint::new(tx_0.compute_txid(), 1),
..Default::default()
}],
- ..common::new_tx(0)
+ ..new_tx(0)
};
// Insert in graph and mark it as seen.
/// Ensure that `last_seen` values only increase during [`Merge::merge`].
#[test]
fn test_changeset_last_seen_merge() {
- let txid: Txid = h!("test txid");
+ let txid: Txid = hash!("test txid");
let test_cases: &[(Option<u64>, Option<u64>)] = &[
(Some(5), Some(6)),
assert_eq!(unseen_txs.len(), 2);
// chain
- let blocks: BTreeMap<u32, BlockHash> = [(0, h!("g")), (1, h!("A")), (2, h!("B"))]
+ let blocks: BTreeMap<u32, BlockHash> = [(0, hash!("g")), (1, hash!("A")), (2, hash!("B"))]
.into_iter()
.collect();
let chain = LocalChain::from_blocks(blocks).unwrap();
TxUpdate {
txs: vec![make_tx(0).into(), make_tx(1).into()],
txouts: [
- (OutPoint::new(h!("a"), 0), make_txout(0)),
- (OutPoint::new(h!("a"), 1), make_txout(1)),
- (OutPoint::new(h!("b"), 0), make_txout(2)),
+ (OutPoint::new(hash!("a"), 0), make_txout(0)),
+ (OutPoint::new(hash!("a"), 1), make_txout(1)),
+ (OutPoint::new(hash!("b"), 0), make_txout(2)),
]
.into(),
..Default::default()
TxUpdate {
txs: vec![make_tx(0).into(), make_tx(1).into()],
txouts: [
- (OutPoint::new(h!("a"), 0), make_txout(0)),
- (OutPoint::new(h!("a"), 1), make_txout(1)),
- (OutPoint::new(h!("b"), 0), make_txout(2)),
+ (OutPoint::new(hash!("a"), 0), make_txout(0)),
+ (OutPoint::new(hash!("a"), 1), make_txout(1)),
+ (OutPoint::new(hash!("b"), 0), make_txout(2)),
]
.into(),
anchors: [
- (ConfirmationBlockTime::default(), h!("a")),
- (ConfirmationBlockTime::default(), h!("b")),
+ (ConfirmationBlockTime::default(), hash!("a")),
+ (ConfirmationBlockTime::default(), hash!("b")),
]
.into(),
..Default::default()
TxUpdate {
txs: vec![make_tx(0).into(), make_tx(1).into()],
txouts: [
- (OutPoint::new(h!("a"), 0), make_txout(0)),
- (OutPoint::new(h!("a"), 1), make_txout(1)),
- (OutPoint::new(h!("d"), 0), make_txout(2)),
+ (OutPoint::new(hash!("a"), 0), make_txout(0)),
+ (OutPoint::new(hash!("a"), 1), make_txout(1)),
+ (OutPoint::new(hash!("d"), 0), make_txout(2)),
]
.into(),
anchors: [
- (ConfirmationBlockTime::default(), h!("a")),
- (ConfirmationBlockTime::default(), h!("b")),
+ (ConfirmationBlockTime::default(), hash!("a")),
+ (ConfirmationBlockTime::default(), hash!("b")),
]
.into(),
- seen_ats: [(h!("c"), 12346)].into_iter().collect(),
+ seen_ats: [(hash!("c"), 12346)].into_iter().collect(),
},
),
];