Solve chainActive-related locking issues
- In wallet and GUI code LOCK cs_main as well as cs_wallet when necessary - In main.cpp SendMessages move the TRY_LOCK(cs_main) up, to encompass the call to IsInitialBlockDownload. - Make ActivateBestChain, AddToBlockIndex, IsInitialBlockDownload, InitBlockIndex acquire the cs_main lock Fixes #3997
This commit is contained in:
parent
e07c943ce8
commit
55a1db4fa2
7 changed files with 269 additions and 272 deletions
15
src/main.cpp
15
src/main.cpp
|
@ -1310,7 +1310,7 @@ int GetNumBlocksOfPeers()
|
|||
|
||||
bool IsInitialBlockDownload()
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
LOCK(cs_main);
|
||||
if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate())
|
||||
return true;
|
||||
static int64_t nLastUpdate;
|
||||
|
@ -2087,7 +2087,7 @@ void static FindMostWorkChain() {
|
|||
|
||||
// Try to activate to the most-work chain (thereby connecting it).
|
||||
bool ActivateBestChain(CValidationState &state) {
|
||||
AssertLockHeld(cs_main);
|
||||
LOCK(cs_main);
|
||||
CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||
bool fComplete = false;
|
||||
while (!fComplete) {
|
||||
|
@ -2136,7 +2136,6 @@ bool ActivateBestChain(CValidationState &state) {
|
|||
|
||||
bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos& pos)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Check for duplicate
|
||||
uint256 hash = block.GetHash();
|
||||
if (mapBlockIndex.count(hash))
|
||||
|
@ -2173,6 +2172,7 @@ bool AddToBlockIndex(CBlock& block, CValidationState& state, const CDiskBlockPos
|
|||
if (!ActivateBestChain(state))
|
||||
return false;
|
||||
|
||||
LOCK(cs_main);
|
||||
if (pindexNew == chainActive.Tip())
|
||||
{
|
||||
// Clear fork warning if its no longer applicable
|
||||
|
@ -2962,6 +2962,7 @@ bool LoadBlockIndex()
|
|||
|
||||
|
||||
bool InitBlockIndex() {
|
||||
LOCK(cs_main);
|
||||
// Check whether we're already initialized
|
||||
if (chainActive.Genesis() != NULL)
|
||||
return true;
|
||||
|
@ -4201,6 +4202,10 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||
}
|
||||
}
|
||||
|
||||
TRY_LOCK(cs_main, lockMain); // Acquire cs_main for IsInitialBlockDownload() and CNodeState()
|
||||
if (!lockMain)
|
||||
return true;
|
||||
|
||||
// Address refresh broadcast
|
||||
static int64_t nLastRebroadcast;
|
||||
if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
|
||||
|
@ -4251,10 +4256,6 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
|
|||
pto->PushMessage("addr", vAddr);
|
||||
}
|
||||
|
||||
TRY_LOCK(cs_main, lockMain);
|
||||
if (!lockMain)
|
||||
return true;
|
||||
|
||||
CNodeState &state = *State(pto->GetId());
|
||||
if (state.fShouldBan) {
|
||||
if (pto->addr.IsLocal())
|
||||
|
|
|
@ -55,6 +55,7 @@ int ClientModel::getNumConnections(unsigned int flags) const
|
|||
|
||||
int ClientModel::getNumBlocks() const
|
||||
{
|
||||
LOCK(cs_main);
|
||||
return chainActive.Height();
|
||||
}
|
||||
|
||||
|
@ -76,6 +77,7 @@ quint64 ClientModel::getTotalBytesSent() const
|
|||
|
||||
QDateTime ClientModel::getLastBlockDate() const
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (chainActive.Tip())
|
||||
return QDateTime::fromTime_t(chainActive.Tip()->GetBlockTime());
|
||||
else
|
||||
|
@ -84,6 +86,7 @@ QDateTime ClientModel::getLastBlockDate() const
|
|||
|
||||
double ClientModel::getVerificationProgress() const
|
||||
{
|
||||
LOCK(cs_main);
|
||||
return Checkpoints::GuessVerificationProgress(chainActive.Tip());
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,7 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
|||
{
|
||||
QString strHTML;
|
||||
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
strHTML.reserve(4000);
|
||||
strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
|
||||
|
||||
|
@ -272,8 +271,6 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
|||
strHTML += "<br><b>" + tr("Inputs") + ":</b>";
|
||||
strHTML += "<ul>";
|
||||
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
BOOST_FOREACH(const CTxIn& txin, wtx.vin)
|
||||
{
|
||||
COutPoint prevout = txin.prevout;
|
||||
|
@ -297,12 +294,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strHTML += "</ul>";
|
||||
}
|
||||
|
||||
strHTML += "</font></html>";
|
||||
}
|
||||
return strHTML;
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
qDebug() << "TransactionTablePriv::refreshWallet";
|
||||
cachedWallet.clear();
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
for(std::map<uint256, CWalletTx>::iterator it = wallet->mapWallet.begin(); it != wallet->mapWallet.end(); ++it)
|
||||
{
|
||||
if(TransactionRecord::showTransaction(it->second))
|
||||
|
@ -96,7 +96,7 @@ public:
|
|||
{
|
||||
qDebug() << "TransactionTablePriv::updateWallet : " + QString::fromStdString(hash.ToString()) + " " + QString::number(status);
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
|
||||
// Find transaction in wallet
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(hash);
|
||||
|
@ -190,10 +190,9 @@ public:
|
|||
// If a status update is needed (blocks came in since last check),
|
||||
// update the status of this transaction from the wallet. Otherwise,
|
||||
// simply re-use the cached status.
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
if(rec->statusUpdateNeeded())
|
||||
{
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
||||
|
||||
if(mi != wallet->mapWallet.end())
|
||||
|
@ -201,7 +200,6 @@ public:
|
|||
rec->updateStatus(mi->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
else
|
||||
|
@ -213,7 +211,7 @@ public:
|
|||
QString describe(TransactionRecord *rec, int unit)
|
||||
{
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
std::map<uint256, CWalletTx>::iterator mi = wallet->mapWallet.find(rec->hash);
|
||||
if(mi != wallet->mapWallet.end())
|
||||
{
|
||||
|
@ -228,17 +226,12 @@ TransactionTableModel::TransactionTableModel(CWallet* wallet, WalletModel *paren
|
|||
QAbstractTableModel(parent),
|
||||
wallet(wallet),
|
||||
walletModel(parent),
|
||||
priv(new TransactionTablePriv(wallet, this)),
|
||||
cachedNumBlocks(0)
|
||||
priv(new TransactionTablePriv(wallet, this))
|
||||
{
|
||||
columns << QString() << tr("Date") << tr("Type") << tr("Address") << tr("Amount");
|
||||
|
||||
priv->refreshWallet();
|
||||
|
||||
QTimer *timer = new QTimer(this);
|
||||
connect(timer, SIGNAL(timeout()), this, SLOT(updateConfirmations()));
|
||||
timer->start(MODEL_UPDATE_DELAY);
|
||||
|
||||
connect(walletModel->getOptionsModel(), SIGNAL(displayUnitChanged(int)), this, SLOT(updateDisplayUnit()));
|
||||
}
|
||||
|
||||
|
@ -257,9 +250,6 @@ void TransactionTableModel::updateTransaction(const QString &hash, int status)
|
|||
|
||||
void TransactionTableModel::updateConfirmations()
|
||||
{
|
||||
if(chainActive.Height() != cachedNumBlocks)
|
||||
{
|
||||
cachedNumBlocks = chainActive.Height();
|
||||
// Blocks came in since last poll.
|
||||
// Invalidate status (number of confirmations) and (possibly) description
|
||||
// for all rows. Qt is smart enough to only actually request the data for the
|
||||
|
@ -267,7 +257,6 @@ void TransactionTableModel::updateConfirmations()
|
|||
emit dataChanged(index(0, Status), index(priv->size()-1, Status));
|
||||
emit dataChanged(index(0, ToAddress), index(priv->size()-1, ToAddress));
|
||||
}
|
||||
}
|
||||
|
||||
int TransactionTableModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
|
|
|
@ -69,7 +69,6 @@ private:
|
|||
WalletModel *walletModel;
|
||||
QStringList columns;
|
||||
TransactionTablePriv *priv;
|
||||
int cachedNumBlocks;
|
||||
|
||||
QString lookupAddress(const std::string &address, bool tooltip) const;
|
||||
QVariant addressColor(const TransactionRecord *wtx) const;
|
||||
|
|
|
@ -98,11 +98,21 @@ void WalletModel::updateStatus()
|
|||
|
||||
void WalletModel::pollBalanceChanged()
|
||||
{
|
||||
bool heightChanged = false;
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if(chainActive.Height() != cachedNumBlocks)
|
||||
{
|
||||
// Balance and number of transactions might have changed
|
||||
cachedNumBlocks = chainActive.Height();
|
||||
heightChanged = true;
|
||||
}
|
||||
}
|
||||
if(heightChanged)
|
||||
{
|
||||
checkBalanceChanged();
|
||||
if(transactionTableModel)
|
||||
transactionTableModel->updateConfirmations();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -520,7 +530,7 @@ bool WalletModel::getPubKey(const CKeyID &address, CPubKey& vchPubKeyOut) const
|
|||
// returns a list of COutputs from COutPoints
|
||||
void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vector<COutput>& vOutputs)
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
BOOST_FOREACH(const COutPoint& outpoint, vOutpoints)
|
||||
{
|
||||
if (!wallet->mapWallet.count(outpoint.hash)) continue;
|
||||
|
@ -533,7 +543,7 @@ void WalletModel::getOutputs(const std::vector<COutPoint>& vOutpoints, std::vect
|
|||
|
||||
bool WalletModel::isSpent(const COutPoint& outpoint) const
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
return wallet->IsSpent(outpoint.hash, outpoint.n);
|
||||
}
|
||||
|
||||
|
@ -543,7 +553,7 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
|
|||
std::vector<COutput> vCoins;
|
||||
wallet->AvailableCoins(vCoins);
|
||||
|
||||
LOCK(wallet->cs_wallet); // ListLockedCoins, mapWallet
|
||||
LOCK2(cs_main, wallet->cs_wallet); // ListLockedCoins, mapWallet
|
||||
std::vector<COutPoint> vLockedCoins;
|
||||
wallet->ListLockedCoins(vLockedCoins);
|
||||
|
||||
|
@ -575,25 +585,25 @@ void WalletModel::listCoins(std::map<QString, std::vector<COutput> >& mapCoins)
|
|||
|
||||
bool WalletModel::isLockedCoin(uint256 hash, unsigned int n) const
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
return wallet->IsLockedCoin(hash, n);
|
||||
}
|
||||
|
||||
void WalletModel::lockCoin(COutPoint& output)
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
wallet->LockCoin(output);
|
||||
}
|
||||
|
||||
void WalletModel::unlockCoin(COutPoint& output)
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
wallet->UnlockCoin(output);
|
||||
}
|
||||
|
||||
void WalletModel::listLockedCoins(std::vector<COutPoint>& vOutpts)
|
||||
{
|
||||
LOCK(wallet->cs_wallet);
|
||||
LOCK2(cs_main, wallet->cs_wallet);
|
||||
wallet->ListLockedCoins(vOutpts);
|
||||
}
|
||||
|
||||
|
|
|
@ -606,7 +606,7 @@ bool CWallet::AddToWalletIfInvolvingMe(const uint256 &hash, const CTransaction&
|
|||
|
||||
void CWallet::SyncTransaction(const uint256 &hash, const CTransaction& tx, const CBlock* pblock)
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
if (!AddToWalletIfInvolvingMe(hash, tx, pblock, true))
|
||||
return; // Not one of ours
|
||||
|
||||
|
@ -834,7 +834,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
|||
|
||||
CBlockIndex* pindex = pindexStart;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
|
||||
// no need to read and scan block, if block was created before
|
||||
// our wallet birthday (as adjusted for block time variability)
|
||||
|
@ -869,7 +869,7 @@ int CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate)
|
|||
|
||||
void CWallet::ReacceptWalletTransactions()
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
BOOST_FOREACH(PAIRTYPE(const uint256, CWalletTx)& item, mapWallet)
|
||||
{
|
||||
const uint256& wtxid = item.first;
|
||||
|
@ -964,7 +964,7 @@ int64_t CWallet::GetBalance() const
|
|||
{
|
||||
int64_t nTotal = 0;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
|
@ -980,7 +980,7 @@ int64_t CWallet::GetUnconfirmedBalance() const
|
|||
{
|
||||
int64_t nTotal = 0;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
|
@ -995,7 +995,7 @@ int64_t CWallet::GetImmatureBalance() const
|
|||
{
|
||||
int64_t nTotal = 0;
|
||||
{
|
||||
LOCK(cs_wallet);
|
||||
LOCK2(cs_main, cs_wallet);
|
||||
for (map<uint256, CWalletTx>::const_iterator it = mapWallet.begin(); it != mapWallet.end(); ++it)
|
||||
{
|
||||
const CWalletTx* pcoin = &(*it).second;
|
||||
|
|
Loading…
Reference in a new issue