Fix csBestBlock/cvBlockChange waiting in rpc/mining

(cherry picked from commit bitcoin/bitcoin@45dd135039)
This commit is contained in:
Pieter Wuille 2018-03-20 21:04:27 -07:00 committed by Larry Ruane
parent 18f443db1c
commit 4693f8165f
3 changed files with 20 additions and 8 deletions

View File

@ -68,6 +68,8 @@ CBlockIndex *pindexBestHeader = NULL;
static std::atomic<int64_t> nTimeBestReceived(0); // Used only to inform the wallet of when we last received a block
CWaitableCriticalSection csBestBlock;
CConditionVariable cvBlockChange;
uint256 hashBestBlock;
int heightBestBlock;
int nScriptCheckThreads = 0;
std::atomic_bool fImporting(false);
std::atomic_bool fReindex(false);
@ -3757,7 +3759,12 @@ void static UpdateTip(CBlockIndex *pindexNew, const CChainParams& chainParams) {
RenderPoolMetrics("sapling", saplingPool);
RenderPoolMetrics("transparent", transparentPool);
cvBlockChange.notify_all();
{
boost::unique_lock<boost::mutex> lock(csBestBlock);
hashBestBlock = pindexNew->GetBlockHash();
heightBestBlock = pindexNew->nHeight;
cvBlockChange.notify_all();
}
}
/**

View File

@ -160,8 +160,13 @@ extern BlockMap mapBlockIndex;
extern std::optional<uint64_t> last_block_num_txs;
extern std::optional<uint64_t> last_block_size;
extern const std::string strMessageMagic;
// These prevent lock-ordering problems in getblocktemplate() RPC
extern CWaitableCriticalSection csBestBlock;
extern CConditionVariable cvBlockChange;
extern uint256 hashBestBlock;
extern int heightBestBlock;
extern std::atomic_bool fImporting;
extern std::atomic_bool fReindex;
extern int nScriptCheckThreads;

View File

@ -607,15 +607,15 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
nTransactionsUpdatedLastLP = nTransactionsUpdatedLast;
}
// Release the main lock while waiting
// Don't call chainActive->Tip() without holding cs_main
LEAVE_CRITICAL_SECTION(cs_main);
{
checktxtime = boost::get_system_time() + boost::posix_time::seconds(10);
boost::unique_lock<boost::mutex> lock(csBestBlock);
while (chainActive.Tip()->GetBlockHash() == hashWatchedChain && IsRPCRunning())
while (hashBestBlock == hashWatchedChain && IsRPCRunning())
{
// Release the main lock while waiting
LEAVE_CRITICAL_SECTION(cs_main);
// Before waiting, generate the coinbase for the block following the next
// block (since this is cpu-intensive), so that when next block arrives,
// we can quickly respond with a template for following block.
@ -629,11 +629,10 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
next_cb_mtx = cached_next_cb_mtx;
}
bool timedout = !cvBlockChange.timed_wait(lock, checktxtime);
ENTER_CRITICAL_SECTION(cs_main);
// Optimization: even if timed out, a new block may have arrived
// while waiting for cs_main; if so, don't discard next_cb_mtx.
if (chainActive.Tip()->GetBlockHash() != hashWatchedChain) break;
if (hashBestBlock != hashWatchedChain) break;
// Timeout: Check transactions for update
if (timedout && mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP) {
@ -643,11 +642,12 @@ UniValue getblocktemplate(const UniValue& params, bool fHelp)
}
checktxtime += boost::posix_time::seconds(10);
}
if (chainActive.Tip()->nHeight != nHeight + 1) {
if (heightBestBlock != nHeight + 1) {
// Unexpected height (reorg or >1 blocks arrived while waiting) invalidates coinbase tx.
next_cb_mtx = nullopt;
}
}
ENTER_CRITICAL_SECTION(cs_main);
if (!IsRPCRunning())
throw JSONRPCError(RPC_CLIENT_NOT_CONNECTED, "Shutting down");