wallet: Add sqlite as an alternative wallet database and use it for new descriptor wallets#19077
Conversation
92552af to
e09e7d7
Compare
|
I've dropped the amalgamation file |
92d36c5 to
20dcff6
Compare
|
Pretty amazing work! Thanks for doing this. Concept ACK on a BDB replacement for descriptor wallets. As for concrete implementation steps, maybe it would make sense to PR the DB flexibility first, then additional storage engines later. |
I don't think it really makes sense to add a database system that we aren't going to use.
I think there's two primary reasons to choose sqlite over an internal format.
#18971 does the DB class stuff that gives us this flexibility. This PR is adding in the storage engine and the logic for CWallet to choose which storage to use. |
930518e to
0ba7d4e
Compare
|
Concept ACK Nice work! Very readable code! |
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
25d9dfa to
76c7093
Compare
|
CONCEPT ACK |
Rewrite uses the VACUUM command which does exactly what we want. A specific advertised use case is to compact a database and ensure that any deleted data is actually deleted.
MakeWalletDatabase no longer has a default DatabaseFormat. Instead callers, like CWallet::Create, need to specify the database type to create if the file does not exist. If it exists and NONE is given, then CreateWalletDatabase will try to autodetect the type.
Descriptor wallets don't support dumpwallet, so make the tests that do dumpwallet legacy wallet only.
|
Rebased. There was a silent merge conflict with #20130. @hebasto @S3RK @promag @Sjors @ryanofsky @meshcollider @fjahr Could you all re-review/re-ACK this so we can merge it before the feature freeze tomorrow? |
ryanofsky
left a comment
There was a problem hiding this comment.
Code review ACK c4a29d0. I am honestly confused about reasons for locking into wallet.dat again when it's so easy now to use a clean format. I assume I'm just very dense, or there's some unstated reason, because the only thing that's been brought up are unrealistic compatibility scenarios (all require actively creating a wallet with non-default descriptor+sqlite option, then trying to using the descriptor+sqlite wallets with old software or scripts and ignoring the results) that we didn't pay attention to with previous PRs like #11687, which did not require any active interfaction.
Changes since previous review were: using pkg-config, naming/whitespace/documentation/quoting/const/log/assert changes, fixing leak if database constructor throws, enabling unconditional fullsync
| `./` | `wallet.dat` | Personal wallet (BDB) with keys and transactions | ||
| `./` | `wallet.dat` | Personal wallet with keys and transactions. May be either a Berkeley DB or SQLite database file. | ||
| `./` | `.walletlock` | Wallet lock file | ||
| `./` | `wallet.dat-journal` | SQLite Rollback Journal file for `wallet.dat`. Usually created at start and deleted on shutdown. A user *must keep it as safe* as the `wallet.dat` file. |
There was a problem hiding this comment.
In commit "Include sqlite3 in documentation" (6c6639a)
If need to update, there are two corrections that could be made:
- Line 69 "Wallets are Berkeley DB (BDB) databases" is no longer true
- Line 76 "Wallet lock file" should say "BDB wallet lock file"
|
re-utACK c4a29d0 |
|
Tested ACK c4a29d0.
@ryanofsky clean format as in different file extension? I think it can be discussed and changed even after feature freeze, just like @achow says in OP. |
There was a problem hiding this comment.
ACK c4a29d0, debug builds and test runs after rebase to latest master @ c2c4dba, some manual testing creating, using, unloading and reloading a few different new sqlite descriptor wallets over several node restarts/shutdowns.
Nice work and reviewing getting this in shape. Looking forward to testing this further.
2020-10-14T21:54:12Z Using SQLite Version 3.33.0
|
reACK c4a29d0 |
|
Re-review ACK c4a29d0 |
|
@meshcollider has declared that he'll be sorely disappointed if he doesn't get to pull the merge trigger on this PR. |
|
re-utACK c4a29d0 Let's go 🚀 |
| status = DatabaseStatus::FAILED_VERIFY; | ||
| return nullptr; | ||
| } | ||
| return db; |
There was a problem hiding this comment.
Does this return path need to set status = DatabaseStatus::SUCCESS;?
I am asking because gcc seems to generate binaries that will inject false positives into valgrind. I haven't found a bug in the code.
Though, the bdb version also seems to set ::SUCCESS, so it might be appropriate here as well?
There was a problem hiding this comment.
I suppose it should, but istm it shouldn't matter. I'm pretty sure we never check status if there isn't a failure.
There was a problem hiding this comment.
Jup, we don't check status if there is no failure. It is just a style question.
There was a problem hiding this comment.
Also happening with clang, so I'll try to fix this
This PR adds a new class
SQLiteDatabasewhich is a subclass ofWalletDatabase. This provides access to a SQLite database that is used to store the wallet records. To keep compatibility with BDB and to complexity of the change down, we don't make use of many SQLite's features. We use it strictly as a key-value store. We create a tablemainwhich has two columns,keyandvalueboth with the typeblob.For new descriptor wallets, we will create a
SQLiteDatabaseinstead of aBerkeleyDatabase. There is no requirement that all SQLite wallets are descriptor wallets, nor is there a requirement that all descriptor wallets be SQLite wallets. This allows for existing descriptor wallets to work as well as keeping open the option to migrate existing wallets to SQLite.We keep the name
wallet.datfor SQLite wallets. We are able to determine which database type to use by searching for specific magic bytes in thewallet.datfile. SQLite begins it's files with a null terminated stringSQLite format 3. BDB has0x00053162at byte 12 (note that the byte order of this integer depends on the system endianness). So when we see that there is awallet.datfile that we want to open, we check for the magic bytes to determine which database system to use.I decided to keep the
wallet.datnaming to keep things like backup script to continue to function as they won't need to be modified to look for a different file name. It also simplifies a couple of things in the implementation and the tests aswallet.datis something that is specifically being looked for. If we don't want this behavior, then I do have another branch which createswallet.sqlitefiles instead, but I find that this direction is easier.