Skip to content

Sqlite db race condition #915

@kirillzh

Description

@kirillzh

Original context from 03/16/2023:
If we get a new address with New n times, and then we get a new address with LastUnused, we get back the n+1th address (expected behavior).

However, if we send funds to the n-th address, the next time we get a new address with LastUnused, we get back the 2n-th address
And shedding a bit more light on the internals that folks on the team was able to uncover:

Long version: The BDK wallet maintains a database (sqlite in our case). When the wallet is sync’d or when a new address is requested, the wallet caches a large (100) batch of script pubkeys (addresses). These scriptpubkeys are stored in a table with the schema keychain [internal or external], child number, scriptpubkey. When the wallet pulls down transaction data from the electrum server, gets a list of the scriptpubkeys from that database table, and then joins that list to the list of transaction IDs that it gets from the electrum server. It uses this combined list to tell what the last-used address index is. For example, it might see that there are transactions for scriptpubkey 1, 3, and 5. So it knows that the next address it should generate (to prevent re-use) is 6. The problem is that in the version of BDK that we rely on, there is no uniqueness constraints on the table containing the list of scriptpubkeys. That means that under some circumstances, the list of scriptpubkeys can be duplicated. So instead of having 0,1,2,3,4,..., we’ve observed the table contain 0,0,0,1,1,1,2,2,2,3,3,3,... When the wallet sync happens, the fetch of the scriptpubkey list would get these duplicates and join them to the list of transactions. Meaning that if the “latest” transaction was on child 3, it might show up as the 9th entry in the list, causing the wallet to think that the next address it needs to generate is the 10th address.

BDK: 0.25.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions