Merge pull request #4058
55a1db4
Solve chainActive-related locking issues (Wladimir J. van der Laan)e07c943
Add AssertLockHeld for cs_main to ChainActive-using functions (Wladimir J. van der Laan)
This commit is contained in:
commit
2bbecc84e2
8 changed files with 284 additions and 269 deletions
24
src/main.cpp
24
src/main.cpp
|
@ -474,6 +474,7 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
|
|||
|
||||
bool IsStandardTx(const CTransaction& tx, string& reason)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (tx.nVersion > CTransaction::CURRENT_VERSION || tx.nVersion < 1) {
|
||||
reason = "version";
|
||||
return false;
|
||||
|
@ -556,6 +557,7 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
|
|||
|
||||
bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Time based nLockTime implemented in 0.1.6
|
||||
if (tx.nLockTime == 0)
|
||||
return true;
|
||||
|
@ -667,6 +669,7 @@ unsigned int GetP2SHSigOpCount(const CTransaction& tx, CCoinsViewCache& inputs)
|
|||
|
||||
int CMerkleTx::SetMerkleBranch(const CBlock* pblock)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
CBlock blockTmp;
|
||||
|
||||
if (pblock == NULL) {
|
||||
|
@ -813,6 +816,7 @@ int64_t GetMinFee(const CTransaction& tx, unsigned int nBytes, bool fAllowFree,
|
|||
bool AcceptToMemoryPool(CTxMemPool& pool, CValidationState &state, const CTransaction &tx, bool fLimitFree,
|
||||
bool* pfMissingInputs, bool fRejectInsaneFee)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (pfMissingInputs)
|
||||
*pfMissingInputs = false;
|
||||
|
||||
|
@ -958,6 +962,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
|
|||
{
|
||||
if (hashBlock == 0 || nIndex == -1)
|
||||
return 0;
|
||||
AssertLockHeld(cs_main);
|
||||
|
||||
// Find the block it claims to be in
|
||||
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashBlock);
|
||||
|
@ -981,6 +986,7 @@ int CMerkleTx::GetDepthInMainChainINTERNAL(CBlockIndex* &pindexRet) const
|
|||
|
||||
int CMerkleTx::GetDepthInMainChain(CBlockIndex* &pindexRet) const
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
int nResult = GetDepthInMainChainINTERNAL(pindexRet);
|
||||
if (nResult == 0 && !mempool.exists(GetHash()))
|
||||
return -1; // Not in chain, not in mempool
|
||||
|
@ -1304,6 +1310,7 @@ int GetNumBlocksOfPeers()
|
|||
|
||||
bool IsInitialBlockDownload()
|
||||
{
|
||||
LOCK(cs_main);
|
||||
if (fImporting || fReindex || chainActive.Height() < Checkpoints::GetTotalBlocksEstimate())
|
||||
return true;
|
||||
static int64_t nLastUpdate;
|
||||
|
@ -1323,6 +1330,7 @@ CBlockIndex *pindexBestForkTip = NULL, *pindexBestForkBase = NULL;
|
|||
|
||||
void CheckForkWarningConditions()
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Before we get past initial download, we cannot reliably alert about forks
|
||||
// (we assume we don't get stuck on a fork before the last checkpoint)
|
||||
if (IsInitialBlockDownload())
|
||||
|
@ -1368,6 +1376,7 @@ void CheckForkWarningConditions()
|
|||
|
||||
void CheckForkWarningConditionsOnNewFork(CBlockIndex* pindexNewForkTip)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// If we are on a fork that is sufficiently large, set a warning flag
|
||||
CBlockIndex* pfork = pindexNewForkTip;
|
||||
CBlockIndex* plonger = chainActive.Tip();
|
||||
|
@ -2078,6 +2087,7 @@ void static FindMostWorkChain() {
|
|||
|
||||
// Try to activate to the most-work chain (thereby connecting it).
|
||||
bool ActivateBestChain(CValidationState &state) {
|
||||
LOCK(cs_main);
|
||||
CBlockIndex *pindexOldTip = chainActive.Tip();
|
||||
bool fComplete = false;
|
||||
while (!fComplete) {
|
||||
|
@ -2162,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
|
||||
|
@ -2344,6 +2355,7 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo
|
|||
|
||||
bool AcceptBlock(CBlock& block, CValidationState& state, CDiskBlockPos* dbp)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Check for duplicate
|
||||
uint256 hash = block.GetHash();
|
||||
if (mapBlockIndex.count(hash))
|
||||
|
@ -2455,6 +2467,7 @@ bool CBlockIndex::IsSuperMajority(int minVersion, const CBlockIndex* pstart, uns
|
|||
|
||||
int64_t CBlockIndex::GetMedianTime() const
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
const CBlockIndex* pindex = this;
|
||||
for (int i = 0; i < nMedianTimeSpan/2; i++)
|
||||
{
|
||||
|
@ -2467,6 +2480,7 @@ int64_t CBlockIndex::GetMedianTime() const
|
|||
|
||||
void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Filter out duplicate requests
|
||||
if (pindexBegin == pnode->pindexLastGetBlocksBegin && hashEnd == pnode->hashLastGetBlocksEnd)
|
||||
return;
|
||||
|
@ -2948,6 +2962,7 @@ bool LoadBlockIndex()
|
|||
|
||||
|
||||
bool InitBlockIndex() {
|
||||
LOCK(cs_main);
|
||||
// Check whether we're already initialized
|
||||
if (chainActive.Genesis() != NULL)
|
||||
return true;
|
||||
|
@ -2983,6 +2998,7 @@ bool InitBlockIndex() {
|
|||
|
||||
void PrintBlockTree()
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// pre-compute tree structure
|
||||
map<CBlockIndex*, vector<CBlockIndex*> > mapNext;
|
||||
for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
|
||||
|
@ -4186,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))
|
||||
|
@ -4236,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());
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
QString TransactionDesc::FormatTxStatus(const CWalletTx& wtx)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
if (!IsFinalTx(wtx, chainActive.Height() + 1))
|
||||
{
|
||||
if (wtx.nLockTime < LOCKTIME_THRESHOLD)
|
||||
|
@ -45,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'>";
|
||||
|
||||
|
@ -271,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;
|
||||
|
@ -296,12 +294,10 @@ QString TransactionDesc::toHTML(CWallet *wallet, CWalletTx &wtx, int vout, int u
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strHTML += "</ul>";
|
||||
}
|
||||
|
||||
strHTML += "</font></html>";
|
||||
}
|
||||
return strHTML;
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *
|
|||
|
||||
void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
// Determine transaction status
|
||||
|
||||
// Find the block the tx is in
|
||||
|
@ -234,6 +235,7 @@ void TransactionRecord::updateStatus(const CWalletTx &wtx)
|
|||
|
||||
bool TransactionRecord::statusUpdateNeeded()
|
||||
{
|
||||
AssertLockHeld(cs_main);
|
||||
return status.cur_num_blocks != chainActive.Height();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,16 +250,12 @@ 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
|
||||
// visible rows.
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -607,7 +607,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
|
||||
|
||||
|
@ -835,7 +835,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)
|
||||
|
@ -870,7 +870,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;
|
||||
|
@ -965,7 +965,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;
|
||||
|
@ -981,7 +981,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;
|
||||
|
@ -996,7 +996,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