[draft]: Introduce SQL schema for wallet#1110
Draft
yyforyongyu wants to merge 695 commits into
Draft
Conversation
yyforyongyu
force-pushed
the
sql-wallet
branch
from
November 4, 2025 06:08
72921ef to
8b399ed
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
2 times, most recently
from
November 12, 2025 14:10
c93d0a1 to
8eade91
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
3 times, most recently
from
November 24, 2025 01:54
0f68bb3 to
2c7f7a1
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
2 times, most recently
from
November 28, 2025 07:24
04cfa4b to
d6ffdfb
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
4 times, most recently
from
December 16, 2025 00:31
823ddd5 to
7bd08f6
Compare
GustavoStingelin
force-pushed
the
sql-wallet
branch
2 times, most recently
from
December 22, 2025 17:52
715a0c0 to
aac7047
Compare
Collaborator
|
just rebased from master |
yyforyongyu
force-pushed
the
sql-wallet
branch
from
January 15, 2026 09:17
aac7047 to
037828b
Compare
Collaborator
Author
|
Pushed a rebase to fix conflicts |
GustavoStingelin
force-pushed
the
sql-wallet
branch
from
January 19, 2026 17:04
037828b to
04b61be
Compare
Coverage Report for CI Build 28857699468Warning No base build found for commit Coverage: 55.557%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsRequires a base build to compare against. How to fix this → Coverage Stats
💛 - Coveralls |
yyforyongyu
force-pushed
the
sql-wallet
branch
from
January 28, 2026 07:35
9175582 to
bf55cd1
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
from
January 28, 2026 07:37
bf55cd1 to
2092024
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
3 times, most recently
from
February 11, 2026 09:00
9778f28 to
1a85fc7
Compare
yyforyongyu
force-pushed
the
sql-wallet
branch
3 times, most recently
from
February 13, 2026 02:59
ee70821 to
d3c67d4
Compare
yyforyongyu
force-pushed
the
interface-wallet
branch
from
March 9, 2026 09:52
d3ff891 to
1fc8b3c
Compare
Add cross-backend coverage proving RewindWallet detaches only the requested wallet and leaves another wallet's transactions and sync state unchanged.
Use the wallet-scoped RewindWallet API for manual rescans, resolving height-only requests to the canonical block hash and header before recording the new sync tip.
DBPutRewind advances the live address manager's in-memory synced tip via SetSyncedTo before txStore.Rollback inside one walletdb update. If the rollback fails, walletdb reverts the bucket write but the in-memory tip stays rewound to a never-persisted fork point. Snapshot the pre-rewind tip and restore it via RestoreSyncedTo on failure, mirroring ApplyScanBatch's synced-tip rollback. Successful rewinds are unchanged.
Use db.Store to load active unmined transactions for rebroadcast while preserving the legacy read path for syncers without store wiring.
Persist filtered-block notification batches through db.Store so transaction updates and sync-tip advancement stay atomic at the store boundary.
Assert connected-block notifications write one transaction batch together with the matching sync-tip update through the Store.
Cover that a bare-multisig output owned through a member pubkey survives the Store batch path instead of being dropped.
Cover that a relevant transaction carrying both a wallet-owned and an unrelated third-party output credits only the owned output.
Add the helpers that convert recovery scan results into Store batch params: horizon merging, horizon flattening, per-output tx params, and the scan-result block shape.
Write recovery scan batches through db.Store so rescans persist tx notifications, horizons, and synced blocks through one store operation.
Route targeted recovery scan results through the Store batch API without advancing the wallet's synced blocks.
Read the synced tip through syncedTip so checkRollback, advanceChainSync, and scanWithRewind use the Store's tip rather than the legacy addrStore tip in store-backed mode.
scanHorizonParams emitted db.ScanHorizon with an empty AccountName, so ApplyScanBatch fell back to numeric account resolution. That is unsafe for imported and imported-xpub accounts, whose Store-facing numbers are masked to 0 and collide with the default derived account. Thread the *RecoveryState into storeScanBatchParams and stamp every emitted horizon with the durable account name resolved from the recovery state, keeping the numeric fallback only for unexpected missing names.
Add coverage proving a confirmed chain.RelevantTx notification builds an ApplyTxBatch whose transaction carries the confirming block while SyncedTo stays nil, so the standalone notification records the confirmed tx without advancing the wallet sync tip.
Add store-backed reads for recovery scan account horizons: ListAccounts for full scans and GetAccount for targeted scans, converting store account metadata into RecoveryState horizon shape. Every imported account is withheld from the horizons, since its number is masked to 0 and would collide with the default derived account in the by-number recovery lookahead. The wiring of these readers into the scan-state loader follows in a later commit.
Cover storeScanHorizons over both the full-scan ListAccounts path and the targeted GetAccount path, including that imported accounts are withheld from the emitted recovery horizons.
Add store-backed loading of active recovery scan addresses through paginated ListAddresses queries, extracting one address per stored script.
Add store-backed loading of UTXOs that recovery scans should watch through ListOutputsToWatch, converting each store UTXO row into the recovery scan credit shape.
Aggregate store-backed horizon, address, and watch-output reads into loadStoreScanData and route wallet and targeted scan-data loading through the store when store wiring is available.
The Store-backed targeted rescan resolved each AccountScope by number in storeScanHorizons. Both Store backends mask an imported account's number to 0, so an imported-xpub target was indistinguishable from the default derived account 0 and could seed the wrong horizon. Resolve the public targets into identity-aware scanTargets up front through the legacy manager, which still keys accounts by their non-masked number. The keyless imported-address bucket is skipped before any Store lookup; every other target carries its durable AccountName, and the Store horizon load prefers the name, mirroring the ScanHorizon contract and the SQL GetHorizonAccount behavior. A number lookup is never issued for an imported target. The legacy walletdb path is unchanged: it still resolves by number, which it does not mask.
Add real-kvdb-backed coverage for the targeted rescan identity fix: a syncer wired over a real, unlocked waddrmgr-backed Store. The keyless imported-address bucket produces no horizon and issues no number lookup (a real by-number lookup would surface ErrAccountNotFound). A setup with the default derived account 0 and an imported-xpub account masked to number 0 resolves the imported target by its durable name, classifies it as imported, and withholds it, so it is never mis-resolved as the default derived account.
The syncer runtime helpers were routed through the transitional Store but kept an "if s.store == nil" branch that fell back to the legacy walletdb DB* helpers, plus two positive "if s.store != nil" scan-data conditionals that did the same. Production newSyncer is always constructed with the wallet's Store, so nil Store is impossible on these migrated paths and the fallback is dead, contradictory design: a migrated runtime path must always use the Store. Remove the nil-store fallbacks from rewindToBlock, syncedBlockHashes, unminedTxns, updateSyncTip, putTxNotifications, putBlockNotifications, putSyncBatch, putTargetedBatch, syncedTip, loadTargetedScanData, and loadWalletScanData so each helper always uses the Store, and rewrite the "store when configured, falling back to the legacy walletdb path" comments to describe the Store-only behavior. The legacy DB* helpers in db_ops.go are left in place for now; they are removed once no non-deferred call site needs them.
newSyncer kept the Store optional behind a variadic syncerStoreConfig, but the migrated runtime paths now always read and write through the Store, so a nil Store is impossible. Drop the variadic and take store and walletID as mandatory positional parameters. Update every newSyncer call site mechanically to pass the Store: production wiring in manager.go, plus the benchmark, db_ops, and syncer test setups. The store-backed test bodies are rewritten in the following commits.
Rewrite the rollback, initialization, run-loop, run-step, wait, and init-chain-sync tests to drive the syncer through the Store instead of the legacy addrStore/walletdb setup: replace setupTestDB and mockAddrStore wiring with walletmock.Store expectations, and add the expectSyncedTip helper that stubs the synced tip via Store.GetWallet. Drop TestLoadScanDataLegacyFallback and TestRewindToBlockFallsBackToLegacy, which covered the now-removed nil-store fallbacks.
Rewrite the scan-strategy, scan-batch, scan-target, advance-chain-sync, fetch-and-filter, dispatch, scan-data loading, and handle-scan-req tests to source horizons, addresses, watched outputs, and the synced tip from the Store via walletmock expectations, replacing the legacy addrStore and walletdb-backed setup.
Rewrite the handle-chain-update, process-chain-update, and broadcast unmined-txn tests to read the synced tip and unmined transactions from the Store via walletmock expectations, and add the serializeTx helper that encodes a transaction for stubbing TxInfo.SerializedTx.
resolveMasterFingerprint read the master HD public key with a direct walletdb.View against the address manager during wallet load. The master public key is public wallet metadata, so route it through Store.GetWallet instead, removing the last direct walletdb transaction for public-metadata reads from wallet/manager.go. To serve the read, add MasterHDPubKey to the waddrmgr.AddrStore interface (already implemented on *waddrmgr.Manager) and have kvdb's GetWallet fill WalletInfo.MasterPubKey from it, tolerating ErrNoExist for shell, watch-only, and pre-master-key wallets. The MasterHDPubKey read is extracted into a small readMasterPubKey helper to keep GetWallet within the complexity limit. The DBCreateWallet/DBLoadWallet create/load path is left as-is: kvdb's Store.CreateWallet is unimplemented and the Store does not return the legacy waddrmgr.Manager/wtxmgr.Store the runtime needs, so that remains justified runtime-construction scope. Passphrase, private-key, and signer flows are unchanged (deferred to ADR 0010). TestManagerLoadSuccess now asserts the loaded wallet's cached master fingerprint is non-zero and matches the create-time value, locking in the Store-routed read.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Open this PR to track rebase conflicts.
TODO: add descriptions and link PRs and issues.