Skip to content

CanonicalReason::Assumed should map to ChainPosition::Confirmed if a direct anchor exists #2088

@ValuedMammal

Description

@ValuedMammal

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.

CanonicalReason::Assumed { descendant } => match descendant {
Some(_) => match self.direct_anchors.get(txid) {
Some(confirmed_anchor) => ChainPosition::Confirmed {
anchor: confirmed_anchor,
transitively: None,
},

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

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: 88a99ba
  • Rust/Cargo version: 1.88.0

Is this blocking production use?

  • Yes
  • No

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions