Resolves Sapling nullifier persistence issue when importing a key.

During a rescan, a CWalletTx was persisted to disk before it had its
note data set.  This meant that upon restart, the CWalletTx would
potentially be missing its nullifiers causing the wallet's balance
to include notes which had already been spent.

The resolution is to ensure that after a rescan, a CWalletTx is
persisted after it has had its nullifiers set correctly.

Co-authored-by: Eirik Ogilvie-Wigley <eirik@z.cash>
This commit is contained in:
Simon 2018-10-11 21:25:53 -07:00
parent 807fb7497f
commit cd10562c73
1 changed files with 19 additions and 1 deletions

View File

@ -2398,6 +2398,9 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
const CChainParams& chainParams = Params();
CBlockIndex* pindex = pindexStart;
std::vector<uint256> myTxHashes;
{
LOCK2(cs_main, cs_wallet);
@ -2418,8 +2421,10 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
ReadBlockFromDisk(block, pindex);
BOOST_FOREACH(CTransaction& tx, block.vtx)
{
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate))
if (AddToWalletIfInvolvingMe(tx, &block, fUpdate)) {
myTxHashes.push_back(tx.GetHash());
ret++;
}
}
SproutMerkleTree sproutTree;
@ -2441,6 +2446,19 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
LogPrintf("Still rescanning. At block %d. Progress=%f\n", pindex->nHeight, Checkpoints::GuessVerificationProgress(chainParams.Checkpoints(), pindex));
}
}
// After rescanning, persist Sapling note data that might have changed, e.g. nullifiers.
// Do not flush the wallet here for performance reasons.
CWalletDB walletdb(strWalletFile, "r+", false);
for (auto hash : myTxHashes) {
CWalletTx wtx = mapWallet[hash];
if (!wtx.mapSaplingNoteData.empty()) {
if (!wtx.WriteToDisk(&walletdb)) {
LogPrintf("Rescanning... WriteToDisk failed to update Sapling note data for: %s\n", hash.ToString());
}
}
}
ShowProgress(_("Rescanning..."), 100); // hide progress dialog in GUI
}
return ret;