Auto-rescan wallets on reorg if note witnesses get out of sync

This commit is contained in:
miketout
2018-10-12 18:05:32 -07:00
parent 83a426bc91
commit 47ab0926c4
5 changed files with 47 additions and 8 deletions

View File

@@ -4048,7 +4048,10 @@ static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMo
CheckForkWarningConditionsOnNewFork(vpindexToConnect.back()); CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
else else
CheckForkWarningConditions(); CheckForkWarningConditions();
// if we need to, rescan wallets
RescanWallets();
return true; return true;
} }

View File

@@ -17,6 +17,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.EraseTransaction.connect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.RescanWallet.connect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn));
g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5)); g_signals.ChainTip.connect(boost::bind(&CValidationInterface::ChainTip, pwalletIn, _1, _2, _3, _4, _5));
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
@@ -33,6 +34,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1)); g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1)); g_signals.EraseTransaction.disconnect(boost::bind(&CValidationInterface::EraseFromWallet, pwalletIn, _1));
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2)); g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2));
g_signals.RescanWallet.disconnect(boost::bind(&CValidationInterface::RescanWallet, pwalletIn));
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1)); g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1));
} }
@@ -45,6 +47,7 @@ void UnregisterAllValidationInterfaces() {
g_signals.UpdatedTransaction.disconnect_all_slots(); g_signals.UpdatedTransaction.disconnect_all_slots();
g_signals.EraseTransaction.disconnect_all_slots(); g_signals.EraseTransaction.disconnect_all_slots();
g_signals.SyncTransaction.disconnect_all_slots(); g_signals.SyncTransaction.disconnect_all_slots();
g_signals.RescanWallet.disconnect_all_slots();
g_signals.UpdatedBlockTip.disconnect_all_slots(); g_signals.UpdatedBlockTip.disconnect_all_slots();
} }
@@ -55,3 +58,7 @@ void SyncWithWallets(const CTransaction &tx, const CBlock *pblock) {
void EraseFromWallets(const uint256 &hash) { void EraseFromWallets(const uint256 &hash) {
g_signals.EraseTransaction(hash); g_signals.EraseTransaction(hash);
} }
void RescanWallets() {
g_signals.RescanWallet();
}

View File

@@ -30,12 +30,15 @@ void UnregisterAllValidationInterfaces();
void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL); void SyncWithWallets(const CTransaction& tx, const CBlock* pblock = NULL);
/** Erase a transaction from all registered wallets */ /** Erase a transaction from all registered wallets */
void EraseFromWallets(const uint256 &hash); void EraseFromWallets(const uint256 &hash);
/** Rescan all registered wallets */
void RescanWallets();
class CValidationInterface { class CValidationInterface {
protected: protected:
virtual void UpdatedBlockTip(const CBlockIndex *pindex) {} virtual void UpdatedBlockTip(const CBlockIndex *pindex) {}
virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {} virtual void SyncTransaction(const CTransaction &tx, const CBlock *pblock) {}
virtual void EraseFromWallet(const uint256 &hash) {} virtual void EraseFromWallet(const uint256 &hash) {}
virtual void RescanWallet() {}
virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {} virtual void ChainTip(const CBlockIndex *pindex, const CBlock *pblock, SproutMerkleTree sproutTree, SaplingMerkleTree saplingTree, bool added) {}
virtual void SetBestChain(const CBlockLocator &locator) {} virtual void SetBestChain(const CBlockLocator &locator) {}
virtual void UpdatedTransaction(const uint256 &hash) {} virtual void UpdatedTransaction(const uint256 &hash) {}
@@ -52,8 +55,10 @@ struct CMainSignals {
boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip; boost::signals2::signal<void (const CBlockIndex *)> UpdatedBlockTip;
/** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */ /** Notifies listeners of updated transaction data (transaction, and optionally the block it is found in. */
boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction; boost::signals2::signal<void (const CTransaction &, const CBlock *)> SyncTransaction;
/** Notifies listeners of an erased transaction (currently disabled, requires transaction replacement). */ /** Notifies listeners of an erased transaction. */
boost::signals2::signal<void (const uint256 &)> EraseTransaction; boost::signals2::signal<void (const uint256 &)> EraseTransaction;
/** Notifies listeners of the need to rescan the wallet. */
boost::signals2::signal<void ()> RescanWallet;
/** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */ /** Notifies listeners of an updated transaction without new data (for now: a coinbase potentially becoming visible). */
boost::signals2::signal<void (const uint256 &)> UpdatedTransaction; boost::signals2::signal<void (const uint256 &)> UpdatedTransaction;
/** Notifies listeners of a change to the tip of the active block chain. */ /** Notifies listeners of a change to the tip of the active block chain. */

View File

@@ -1123,7 +1123,7 @@ void CWallet::IncrementNoteWitnesses(const CBlockIndex* pindex,
} }
template<typename NoteDataMap> template<typename NoteDataMap>
void DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize) bool DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t nWitnessCacheSize)
{ {
extern int32_t KOMODO_REWIND; extern int32_t KOMODO_REWIND;
@@ -1138,7 +1138,11 @@ void DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t n
// Witnesses being decremented should always be either -1 // Witnesses being decremented should always be either -1
// (never incremented or decremented) or equal to the height // (never incremented or decremented) or equal to the height
// of the block being removed (indexHeight) // of the block being removed (indexHeight)
assert((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight)); if (!((nd->witnessHeight == -1) || (nd->witnessHeight == indexHeight)))
{
printf("at height %d\n", indexHeight);
return false;
}
if (nd->witnesses.size() > 0) { if (nd->witnesses.size() > 0) {
nd->witnesses.pop_front(); nd->witnesses.pop_front();
} }
@@ -1163,14 +1167,17 @@ void DecrementNoteWitnesses(NoteDataMap& noteDataMap, int indexHeight, int64_t n
} }
} }
assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0); assert(KOMODO_REWIND != 0 || nWitnessCacheSize > 0);
return true;
} }
void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex) void CWallet::DecrementNoteWitnesses(const CBlockIndex* pindex)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) { for (std::pair<const uint256, CWalletTx>& wtxItem : mapWallet) {
::DecrementNoteWitnesses(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize); if (!::DecrementNoteWitnesses(wtxItem.second.mapSproutNoteData, pindex->GetHeight(), nWitnessCacheSize))
::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize); needsRescan = true;
if (!::DecrementNoteWitnesses(wtxItem.second.mapSaplingNoteData, pindex->GetHeight(), nWitnessCacheSize))
needsRescan = true;
} }
nWitnessCacheSize -= 1; nWitnessCacheSize -= 1;
// TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302) // TODO: If nWitnessCache is zero, we need to regenerate the caches (#1302)
@@ -1838,6 +1845,17 @@ void CWallet::EraseFromWallet(const uint256 &hash)
return; return;
} }
void CWallet::RescanWallet()
{
if (needsRescan)
{
CBlockIndex *start = chainActive.Height() > 0 ? chainActive[1] : NULL;
if (start)
ScanForWalletTransactions(start, true);
needsRescan = false;
}
}
/** /**
* Returns a nullifier if the SpendingKey is available * Returns a nullifier if the SpendingKey is available
@@ -3001,6 +3019,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
// Sort them in chronological order // Sort them in chronological order
multimap<unsigned int, CWalletTx*> mapSorted; multimap<unsigned int, CWalletTx*> mapSorted;
uint32_t now = (uint32_t)time(NULL); uint32_t now = (uint32_t)time(NULL);
std::vector<uint256> vwtxh;
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet) BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
{ {
CWalletTx& wtx = item.second; CWalletTx& wtx = item.second;
@@ -3012,8 +3031,7 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
if ( wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME ) if ( wtx.nLockTime >= LOCKTIME_THRESHOLD && wtx.nLockTime < now-KOMODO_MAXMEMPOOLTIME )
{ {
LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now); LogPrintf("skip Relaying wtx %s nLockTime %u vs now.%u\n", wtx.GetHash().ToString(),(uint32_t)wtx.nLockTime,now);
//TODO: EraseFromWallet(wtx.GetHash()); //should be erased, but this creates issues, likely better to create vwtxh.push_back(wtx.GetHash());
// vector and do it outside of this loop, but for later
continue; continue;
} }
} }
@@ -3028,6 +3046,10 @@ std::vector<uint256> CWallet::ResendWalletTransactionsBefore(int64_t nTime)
result.push_back(wtx.GetHash()); result.push_back(wtx.GetHash());
} }
} }
for (auto hash : vwtxh)
{
EraseFromWallet(hash);
}
return result; return result;
} }

View File

@@ -781,6 +781,7 @@ public:
* incremental witness cache in any transaction in mapWallet. * incremental witness cache in any transaction in mapWallet.
*/ */
int64_t nWitnessCacheSize; int64_t nWitnessCacheSize;
bool needsRescan = false;
void ClearNoteWitnessCache(); void ClearNoteWitnessCache();
@@ -1120,6 +1121,7 @@ public:
bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb); bool AddToWallet(const CWalletTx& wtxIn, bool fFromLoadWallet, CWalletDB* pwalletdb);
void EraseFromWallet(const uint256 &hash); void EraseFromWallet(const uint256 &hash);
void SyncTransaction(const CTransaction& tx, const CBlock* pblock); void SyncTransaction(const CTransaction& tx, const CBlock* pblock);
void RescanWallet();
bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate); bool AddToWalletIfInvolvingMe(const CTransaction& tx, const CBlock* pblock, bool fUpdate);
void WitnessNoteCommitment( void WitnessNoteCommitment(
std::vector<uint256> commitments, std::vector<uint256> commitments,