bitcoindevkit / bitcoindevkit/bdk_wallet

Import `exportwatchonly` wallet

Open
#539 2 comments 0 reactions 0 assignees View on GitHub
new feature
Dominant language
Rust
Stars
59
Forks
105
Avg merge
10d 9h
Merged PRs (30d)
1

Description

**Describe the enhancement**

BDK Wallet should be able to import (watch-only) wallet created by the new [`exportwatchonly`](https://github.com/bitcoin/bitcoin/pull/32489) rpc.

**Use case**

Applications using `bdk_wallet` would be able to easily and efficiently import a Bitcoin Core Wallet.

**Impact**
- [ ] Blocking production usage
- [x] Nice-to-have / UX improvement
- [ ] Developer experience / maintainability

**Are you using BDK in a production project?**
- [ ] Yes
- [x] No
- [ ] Not yet, but planning to

**Which backend(s) are relevant (if any)?**
- [ ] Electrum
- [ ] Esplora
- [ ] Bitcoin Core RPC
- [x] None / not backend-related (e.g. `bdk_chain`, `bdk_core`)
- [ ] Other (please specify): `____`

**Project or organization (optional)**

**Additional context**

The exported wallet has the same format as a regular Bitcoin Core Wallet just without private keys (and hence `WALLET_FLAG_DISABLE_PRIVATE_KEYS` flag enabled). Therefore it consists of
a Sqlite table (called `main`) with two columns (`key` and `value`). Both the columns have the
BLOB type.

|PRAGMA | Value | Corresponding BDK Structure|
|-- | -- | --|
|"application_id" | Network Magic as string | Network|
|"user_version" | Sqlite Schema Version (0) | KeyRing(?) (Required for Round Trip)|

Sqlite Table:

| Key | Value | Corresponding BDK Structure |
| --- | --- | --- |
| `"version"` | Bitcoin Core Client Version (u32) | KeyRing(?) (Required for Round Trip) |
| `"flags"` | Wallet Flags Bitmask (u64) | KeyRing(?) (Required for Round Trip) |
| `("walletdescriptor", descriptorid)` | WalletDescriptor | Keyring |
| `("activeexternalspk", output_type)` | descriptorid | KeyRing/Wallet |
| `("activeinternalspk", output_type)` | descriptorid | KeyRing/Wallet |
| `(("walletdescriptorcache", descriptorid), expression_index)` | CExtPubKey | N/A (Construct for round trip) |
| `(("walletdescriptorcache", descriptorid), (expression_index, der_index))` | CExtPubKey | N/A (Construct for round trip) |
| `(("walletdescriptorlhcache", descriptorid), expression_index )` | CExtPubKey | N/A(Contruct for round trip) |
| `("tx", txid)` | CWalletTx | Tx_graph |
| `("wtxvariant",(txid, wtxid))` | CTransaction | Tx_graph |
| `("lockedutxo" , (txid, vout))` | 0x31 | Currently no structure/Locked Outpoints in `Wallet` finally? |
| `"bestblock_nomerkle"` | CBlockLocator | LocalChain |
| `"bestblock"` | CBlockLocator(Empty) | N/A (Construct for round trip) |
| `"orderposnext"` | u64 | ? |
| `("purpose", address-string)` | Purpose-string | Need Labels |
| `("name", address-string)` | Label-string | Need Labels |
| `("destdata",(address-string, "rr"+ id-string))` | Bip21-request-string | Need Labels |
| `("destdata", (address-string, "used"))` | 0x31 | Need Labels |

Points to note:
- Strings are serialized with a CompactSize length prefix.
- Tuples and Pairs (e.g., std::make_pair(A, B)) are serialized simply by serializing A immediately followed by B.
- descriptorid is a u256
- output_type is a u8
- The descriptor cache has 3 variants:
- m_parent_xpubs: Cache of XPubs just before the wildcard level (if the wildcard is not hardened).
- m_last_hardened_xpubs: Cache of XPubs at the last hardened level (if the wildcard is not hardened and if there is any hardened level).
- m_derived_xpubs: Cache of XPubs at the wildcard level in case the wildcard is hardened.
- expression_index is the position of the key in the descriptor.
- der_index is needed when
- txid and wtxid are u256
- CWalletTx also contains the blockhash the tx is anchored at, the position of the tx in the block and the time at which the tx was received by node (could be the first_seen).
- wtxvariant are the (currently) non-canonical versions of the Tx which have different wtxid.
- vout is a u32.
- How do we remember the nOrderPos corresponding to each transaction?
- id-string is the Bitcoin Wallet's internal enumeration of the Bip21 requests for the address.

This needs #524 and #168 .

Contributor guide

Open the contributing guide

Research direction

Start with the exportwatchonly RPC description and the SQLite `main` table mappings in this issue, then review dependencies #524 and #168. Determine how descriptors, transactions, chain state, flags, and labels map into bdk_wallet while preserving the required round-trip data. Done means a Bitcoin Core watch-only export can be imported and validated against the documented schema.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, sqlite
Domain
database
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.