Use a signal to continue init after genesis activation

Zcash: We set the Sprout tree root on the genesis block's index file in
InitBlockIndex because we were implicitly relying on this occurring via
ActivateBestChain previously.

(cherry picked from commit bitcoin/bitcoin@0fd2a33648)
This commit is contained in:
Pieter Wuille 2016-07-22 15:57:25 +02:00 committed by Jack Grigg
parent 730d245cea
commit 084906c845
3 changed files with 40 additions and 12 deletions

View File

@ -554,6 +554,21 @@ static void TxExpiryNotifyCallback(const uint256& txid)
boost::thread t(runCommand, strCmd); // thread runs free
}
static bool fHaveGenesis = false;
static boost::mutex cs_GenesisWait;
static CConditionVariable condvar_GenesisWait;
static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex)
{
if (pBlockIndex != NULL) {
{
boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait);
fHaveGenesis = true;
}
condvar_GenesisWait.notify_all();
}
}
struct CImportingNow
{
CImportingNow() {
@ -1705,7 +1720,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
break;
}
if (!fReindex) {
if (!fReindex && chainActive.Tip() != NULL) {
uiInterface.InitMessage(_("Rewinding blocks if needed..."));
if (!RewindBlockIndex(chainparams, clearWitnessCaches)) {
strLoadError = _("Unable to rewind the database to a pre-upgrade state. You will need to redownload the blockchain");
@ -1862,6 +1877,14 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// ********************************************************* Step 10: import blocks
// Either install a handler to notify us when genesis activates, or set fHaveGenesis directly.
// No locking, as this happens before any background thread is started.
if (chainActive.Tip() == NULL) {
uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait);
} else {
fHaveGenesis = true;
}
if (mapArgs.count("-blocknotify"))
uiInterface.NotifyBlockTip.connect(BlockNotifyCallback);
@ -1874,19 +1897,16 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
for (const std::string& strFile : mapMultiArgs["-loadblock"])
vImportFiles.push_back(strFile);
}
threadGroup.create_thread(boost::bind(&ThreadImport, vImportFiles, chainparams));
// Wait for genesis block to be processed
bool fHaveGenesis = false;
while (!fHaveGenesis && !fRequestShutdown) {
{
LOCK(cs_main);
fHaveGenesis = (chainActive.Tip() != NULL);
}
if (!fHaveGenesis) {
MilliSleep(10);
{
boost::unique_lock<boost::mutex> lock(cs_GenesisWait);
while (!fHaveGenesis) {
condvar_GenesisWait.wait(lock);
}
uiInterface.NotifyBlockTip.disconnect(BlockNotifyGenesisWait);
}
if (!fHaveGenesis) {
return false;

View File

@ -5818,8 +5818,11 @@ bool InitBlockIndex(const CChainParams& chainparams)
CBlockIndex *pindex = AddToBlockIndex(block, chainparams.GetConsensus());
if (!ReceivedBlockTransactions(block, state, chainparams, pindex, blockPos))
return error("LoadBlockIndex(): genesis block not accepted");
if (!ActivateBestChain(state, chainparams, &block))
return error("LoadBlockIndex(): genesis block cannot be activated");
// Before the genesis block, there was an empty tree. We set its root here so
// that the block import thread doesn't race other methods that need to query
// the Sprout tree (namely CWallet::ScanForWalletTransactions).
SproutMerkleTree tree;
pindex->hashSproutAnchor = tree.root();
// Force a chainstate write so that when we VerifyDB in a moment, it doesn't check stale data
return FlushStateToDisk(chainparams, state, FLUSH_STATE_ALWAYS);
} catch (const std::runtime_error& e) {

View File

@ -90,6 +90,11 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
InitBlockIndex(chainparams);
{
CValidationState state;
bool ok = ActivateBestChain(state, chainparams);
BOOST_CHECK(ok);
}
nScriptCheckThreads = 3;
for (int i=0; i < nScriptCheckThreads-1; i++)
threadGroup.create_thread(&ThreadScriptCheck);