Skip to content

SpkTxOutIndex::is_used returns true for untracked indices #2444

Open

Description

@bhuvan-somisetty

Describe the bug

SpkTxOutIndex::is_used returns true for an index that was never added to or tracked by the index (i.e. not present in self.spks).

Because is_used is implemented as:

pub fn is_used(&self, index: &I) -> bool {
    !self.unused.contains(index)
}

and self.unused only tracks indices that were explicitly added via insert_spk, any index that has never been tracked is absent from self.unused. As a result, !self.unused.contains(index) evaluates to true.

Consequently:

  • On a newly initialized or empty SpkTxOutIndex::<u32>::default(), querying index.is_used(&0) returns true even though no script pubkeys have ever been added.
  • In KeychainTxOutIndex, querying keychain_txout.is_used(keychain, untracked_index) similarly returns true for any derivation index that has not been revealed or tracked.

In contrast, unmark_used in SpkTxOutIndex already explicitly guards against untracked indices:

if !self.spks.contains_key(index) {
    return false;
}

To Reproduce

Run the following unit test in crates/chain/tests/test_spk_txout_index.rs:

#[test]
fn is_used_returns_false_for_untracked_index() {
    let index = SpkTxOutIndex::<u32>::default();
    assert!(!index.is_used(&0));
}

The assertion fails:

assertion failed: !index.is_used(&0)

Similarly, on KeychainTxOutIndex:

let keychain_txout = KeychainTxOutIndex::<Keychain>::default();
assert!(!keychain_txout.is_used(&Keychain::External, 0));

returns true for any unrevealed derivation index.

Expected behavior

is_used should return false for untracked indices (indices not present in self.spks), and only return true for indices that are tracked in self.spks and have been marked used (i.e. not in self.unused).

Build environment

  • BDK tag/commit: f2528da88b1041bdddf547d677511aea19ad3573
  • OS+version: Windows 11
  • Rust/Cargo version: 1.99.0
  • Rust/Cargo target: x86_64-pc-windows-gnullvm

Which backend(s) are relevant (if any)?

  • Electrum
  • Esplora
  • Bitcoin Core RPC
  • None / not backend-related (e.g. bdk_chain, bdk_core)
  • Other (please specify): ____

Is this blocking production use?

  • Yes
  • No

Additional context

Checking self.spks.contains_key(index) ensures that untracked indices are not mistakenly reported as used:

pub fn is_used(&self, index: &I) -> bool {
    self.spks.contains_key(index) && !self.unused.contains(index)
}

Activity

  1. moved this from Triage to In Progress in BDK Chainon Oct 28, 2026
  2. added 2 commits that reference this issue on Nov 2, 2026
    d1821e1
    1cf692d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    • Status
      In Progress

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions