bdk icon indicating copy to clipboard operation
bdk copied to clipboard

fetch_index can mutate the database and increment the index

Open nickfarrow opened this issue 3 years ago • 2 comments

wallet.fetch_index(KeychainKind) can mutate the database which can lead to unexpected results.

For example, the two following snippets give different addresses with a fresh wallet:

dbg!(wallet.get_address(New).unwrap().to_string());
wallet.fetch_index(KeychainKind::External).unwrap();
dbg!(wallet.get_address(New).unwrap().to_string());

In the 2nd case, since no index exists yet in the database, fetch_index follows the else path which fetches and increments the index:

fn fetch_index(&self, keychain: KeychainKind) -> Result<u32, Error> {
    let (descriptor, keychain) = self._get_descriptor_for_keychain(keychain);
    let index = match descriptor.is_deriveable() {
        false => Some(0),
        true => self.database.borrow_mut().get_last_index(keychain)?,
    };

    if let Some(i) = index {
        Ok(i)
    } else {
        // HERE
        self.fetch_and_increment_index(keychain)
    }
}

Perhaps fetch_index should just return None for fresh wallets?

Would replacing fetch_index with fetch_next_derivation_index fix this?

Thoughts/other solutions?

nickfarrow avatar Aug 04 '22 03:08 nickfarrow

This seems like quite a severe bug to me. Very easy to design something that skips the first address. My weak preference is to do the next_derivation_index solution since that's what I did in bdk_core.

FWIW the approach in bdk_core is to simply not have this keychain index. Rather you can simply look at the last address you've derived. It doesn't make sense to derive more than you need in bdk_core. If you are deriving addresses because you are in a watch only mode that's fine but then it doesn't make sense to "get a new address" because you should not be giving out addresses at all.

LLFourn avatar Aug 04 '22 04:08 LLFourn

Imo the fetch index/get address logic is super confusing. It can do with some cleanup.

evanlinjin avatar Aug 04 '22 09:08 evanlinjin

@nickfarrow have you seen this issue with 1.0.0-alpha? If it's fixed in 1.0.0-alpha I'd like to close this issue.

notmandatory avatar Mar 18 '24 04:03 notmandatory