bitcoindevkit / bitcoindevkit/bdk
`CanonicalReason::Assumed` should map to `ChainPosition::Confirmed` if a direct anchor exists
- Dominant language
- Rust
- Stars
- 1.1k
- Forks
- 483
- Avg merge
- 20d 3h
- Merged PRs (30d)
- 3
Description
**Describe the bug**
I tried to pass a `Txid` to `CanonicalizationParams::assume_canonical`, which I expected to be confirmed by a direct anchor, but in the set of canonical txs that is returned the chain position of the assumed tx appeared as `ChainPosition::Unconfirmed`. This later caused unexpected results at the time of doing coin selection.
Currently when a txid is assumed to be canonical, returning a chain position of `ChainPosition::Confirmed` is only possible if the `CanonicalReason`'s `descendant` has some value. https://github.com/bitcoindevkit/bdk/blob/09ddfb2853bb312fd832c6c15330dcaad43af6ac/crates/chain/src/canonical_view.rs#L156-L161
**Expected behavior**
`CanonicalReason::Assumed` should map to `ChainPosition::Confirmed` if a direct anchor exists.
- If the reason carries a `descendant` txid that is confirmed by a direct anchor, I would expect a chain position that is transitively confirmed by the descendant.
- If the assumed tx is confirmed by a direct anchor and is not accompanied by a `descendant`, I would expect a chain position that is confirmed by the direct anchor and a `transitively` of `None`.
- If neither the assumed tx nor a descendant are confirmed by a direct anchor, I would expect `ChainPosition::Unconfirmed`.
**To Reproduce**
I added this test case to demonstrate what I think is the expected behavior. Notice `B` is both assumed and confirmed.
> `test_tx_graph_conflicts.rs`
```rust
Scenario {
name: "B and C are confirmed, C1 spends C, all are assume-canonical",
tx_templates: &[
TxTemplate {
tx_name: "B",
inputs: &[TxInTemplate::Bogus],
outputs: &[TxOutTemplate::new(10_000, Some(0))],
anchors: &[block_id!(1, "B")],
last_seen: None,
assume_canonical: true,
},
TxTemplate {
tx_name: "C",
inputs: &[TxInTemplate::Bogus],
outputs: &[TxOutTemplate::new(8_000, Some(0))],
anchors: &[block_id!(2, "C")],
last_seen: None,
assume_canonical: true,
},
TxTemplate {
tx_name: "C1",
inputs: &[TxInTemplate::PrevTx("C", 0)],
outputs: &[TxOutTemplate::new(6_000, Some(0))],
assume_canonical: true,
..Default::default()
}
],
exp_chain_txs: HashSet::from(["B", "C", "C1"]),
exp_chain_txouts: HashSet::from([("B", 0), ("C", 0), ("C1", 0)]),
exp_unspents: HashSet::from([("B", 0), ("C1", 0)]),
exp_balance: Balance {
immature: Amount::ZERO,
trusted_pending: Amount::from_sat(6_000),
untrusted_pending: Amount::ZERO,
confirmed: Amount::from_sat(10_000),
}
}
```
**Build environment**
- BDK tag/commit: 09ddfb2853bb312fd832c6c15330dcaad43af6ac
- Rust/Cargo version: 1.88.0
**Is this blocking production use?**
- [ ] Yes
- [x] No
Contributor guide
Assessment
This issue has not been assessed yet.