Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for an async Database in Wallet<D> #795

Closed
Tracked by #31
garydevenay opened this issue Nov 6, 2022 · 5 comments
Closed
Tracked by #31

Support for an async Database in Wallet<D> #795

garydevenay opened this issue Nov 6, 2022 · 5 comments
Assignees
Labels
api A breaking API change module-wallet new feature New feature or request
Milestone

Comments

@garydevenay
Copy link

Describe the enhancement
The current storage backends don't have support for async operations. After speaking with @afilini briefly on Discord about this, it's clear that BDK 1.0/bdk_core should give us better support for that.

Since we are a few months away from the bdk_core release, I'm proposing to create an async capable SqliteDatabase (PooledSqliteDatabase?) that will allow us to access a pool of connections across threads and serve as a bridge until the 1.0 release.

Use case

  • Allow our Wallet to be used across threads safely.
  • Serve as a temporary implementation avenue for async applications
@LLFourn
Copy link
Contributor

LLFourn commented Nov 8, 2022

Hey @garydevenay. There's a lot of simplifications coming up for v1.0 in how this is done. There are two things you need to be able to store:

  1. Raw transaction data. This includes full transactions and list of outputs at a Txid. Essentially an append only list of TxNode.
  2. A list of compact transactions in the form (Txid, confirmation_height) and "checkpoints" (height, blockhash). The primary key for the transactions would be the txid while for the checkpoints the height would be the primary key.

You don't need to provide any indexes for these things. Being able to iterate over the records and slurp them all into memory is all that is required.

If you wanted to get started now I'd say at a low level API you'd need in bdk v1.0 would be something like the API of ChainGraph:

https://github.com/LLFourn/bdk_core_staging/blob/17e06985cf2a7d5f2f5a5520f1385a64b448ef59/bdk_core/src/chain_graph.rs#L16

but instead of inserting things into memory it would insert into a database. It wouldn't need to do the apply_update thing though or to check the consistency of what you are being told to insert.

One good reason not to get started now is that we are in the middle of adding "associated data" to transactions so you can store things like the position in the block and/or timestamp or even some application data along with the txid. For sqlite you're going to probably going to have to have a trait you can offer to support this so you know how to store this additional data (which may be application defined).

@garydevenay
Copy link
Author

garydevenay commented Nov 9, 2022

Hey @LLFourn, thanks for those notes.

Agree the v1.0 release will make this a lot easier. As that seems to be months away, my approach for this will be to implement the existing Database trait that uses a pool of Sqlite connections to allow Wallet to be passed between threads.

I will be taking the existing migrations, tables, and queries from the SqliteDatabase implementation that is currently included.

I understand that there may be better future opportunities to start that, but it's currently a large blocker for me at the moment.

Example method:

async fn insert_script_pubkey(&self, keychain: String, child: u32, script: &[u8]) -> Result<i64, bdk::Error> {
    let mut conn = self.pool.acquire().await?;
    let id = sqlx::query!(
        "INSERT INTO script_pubkeys (keychain, child, script) VALUES (?1, ?2, ?3)",
        keychain,
        child,
        script,
    ).execute(&mut conn).await?;

    Ok(id)
}

Edit (10/11/22): I'm also open to writing an implementation for this in bdk_core afterward. But going to focus on having something work in the currently released versions first.

@notmandatory notmandatory added this to the Alpha 1.0.0 milestone Mar 2, 2023
@notmandatory notmandatory removed this from the 1.0.0-alpha.0 milestone Mar 3, 2023
@notmandatory notmandatory added module-wallet api A breaking API change labels Mar 17, 2024
@notmandatory notmandatory added this to the 1.0.0-alpha milestone Mar 17, 2024
@notmandatory
Copy link
Member

Need to verify we can do this with new 1.0 wallet api.

@LLFourn
Copy link
Contributor

LLFourn commented Mar 17, 2024

The example above doesn't apply here since we don't insert script pubkeys in the database anyway as part of BDK's architecture atm. In general I think you can't get the next address (which persists the newly revealed derivation index) in an async manner which is what would frustrate async database users most. It's possible to make async versions of just the address deriving methods which actually need to wait until the async backend has successfully responded (with updating chain data we don't really care whether it was successfully persisted right away -- at least if #1005 is done).

@nondiremanuel nondiremanuel removed this from the 1.0.0-alpha milestone Mar 21, 2024
@evanlinjin
Copy link
Member

Done in #1454 and #1473

@notmandatory notmandatory added this to the 1.0.0-alpha milestone Jun 24, 2024
@notmandatory notmandatory self-assigned this Jun 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api A breaking API change module-wallet new feature New feature or request
Projects
Archived in project
Development

No branches or pull requests

5 participants