Add CWallet::BlockUntilSyncedToCurrentChain()

This blocks until the wallet has synced up to the current height.
This commit is contained in:
Matt Corallo 2017-01-17 18:06:16 -05:00
parent 0b2f42d737
commit 5ee3172636
2 changed files with 57 additions and 2 deletions

View File

@ -33,6 +33,7 @@
#include "wallet/fees.h" #include "wallet/fees.h"
#include <assert.h> #include <assert.h>
#include <future>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
#include <boost/thread.hpp> #include <boost/thread.hpp>
@ -1232,6 +1233,8 @@ void CWallet::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const
for (size_t i = 0; i < pblock->vtx.size(); i++) { for (size_t i = 0; i < pblock->vtx.size(); i++) {
SyncTransaction(pblock->vtx[i], pindex, i); SyncTransaction(pblock->vtx[i], pindex, i);
} }
m_last_block_processed = pindex;
} }
void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) { void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
@ -1244,6 +1247,36 @@ void CWallet::BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) {
void CWallet::BlockUntilSyncedToCurrentChain() {
AssertLockNotHeld(cs_main);
AssertLockNotHeld(cs_wallet);
{
// Skip the queue-draining stuff if we know we're caught up with
// chainActive.Tip()...
// We could also take cs_wallet here, and call m_last_block_processed
// protected by cs_wallet instead of cs_main, but as long as we need
// cs_main here anyway, its easier to just call it cs_main-protected.
LOCK(cs_main);
const CBlockIndex* initialChainTip = chainActive.Tip();
if (m_last_block_processed->GetAncestor(initialChainTip->nHeight) == initialChainTip) {
return;
}
}
// ...otherwise put a callback in the validation interface queue and wait
// for the queue to drain enough to execute it (indicating we are caught up
// at least with the time we entered this function).
std::promise<void> promise;
CallFunctionInValidationInterfaceQueue([&promise] {
promise.set_value();
});
promise.get_future().wait();
}
isminetype CWallet::IsMine(const CTxIn &txin) const isminetype CWallet::IsMine(const CTxIn &txin) const
{ {
{ {
@ -3900,8 +3933,6 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart); LogPrintf(" wallet %15dms\n", GetTimeMillis() - nStart);
RegisterValidationInterface(walletInstance);
// Try to top up keypool. No-op if the wallet is locked. // Try to top up keypool. No-op if the wallet is locked.
walletInstance->TopUpKeyPool(); walletInstance->TopUpKeyPool();
@ -3913,6 +3944,10 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
if (walletdb.ReadBestBlock(locator)) if (walletdb.ReadBestBlock(locator))
pindexRescan = FindForkInGlobalIndex(chainActive, locator); pindexRescan = FindForkInGlobalIndex(chainActive, locator);
} }
walletInstance->m_last_block_processed = chainActive.Tip();
RegisterValidationInterface(walletInstance);
if (chainActive.Tip() && chainActive.Tip() != pindexRescan) if (chainActive.Tip() && chainActive.Tip() != pindexRescan)
{ {
//We can't rescan beyond non-pruned blocks, stop and throw an error //We can't rescan beyond non-pruned blocks, stop and throw an error

View File

@ -722,6 +722,18 @@ private:
std::unique_ptr<CWalletDBWrapper> dbw; std::unique_ptr<CWalletDBWrapper> dbw;
/**
* The following is used to keep track of how far behind the wallet is
* from the chain sync, and to allow clients to block on us being caught up.
*
* Note that this is *not* how far we've processed, we may need some rescan
* to have seen all transactions in the chain, but is only used to track
* live BlockConnected callbacks.
*
* Protected by cs_main (see BlockUntilSyncedToCurrentChain)
*/
const CBlockIndex* m_last_block_processed;
public: public:
/* /*
* Main wallet lock. * Main wallet lock.
@ -1106,6 +1118,14 @@ public:
caller must ensure the current wallet version is correct before calling caller must ensure the current wallet version is correct before calling
this function). */ this function). */
bool SetHDMasterKey(const CPubKey& key); bool SetHDMasterKey(const CPubKey& key);
/**
* Blocks until the wallet state is up-to-date to /at least/ the current
* chain at the time this function is entered
* Obviously holding cs_main/cs_wallet when going into this call may cause
* deadlock
*/
void BlockUntilSyncedToCurrentChain();
}; };
/** A key allocated from the key pool. */ /** A key allocated from the key pool. */