Browse Source

Merge pull request #4148

18e7216 Push cs_mains down in ProcessBlock (Pieter Wuille)
202e019 Move all post-chaintip-change notifications to ActivateBestChain (Pieter Wuille)
4e0eed8 Allow ActivateBestChain to release its lock on cs_main (Pieter Wuille)
77339e5 Get rid of the static chainMostWork (optimization) (Pieter Wuille)
try
Wladimir J. van der Laan 11 years ago
parent
commit
07b233a1b6
No known key found for this signature in database GPG Key ID: 74810B012346C9A6
  1. 176
      src/main.cpp
  2. 6
      src/main.h
  3. 2
      src/miner.cpp
  4. 2
      src/rpcserver.cpp

176
src/main.cpp

@ -40,7 +40,6 @@ CTxMemPool mempool;
map<uint256, CBlockIndex*> mapBlockIndex;
CChain chainActive;
CChain chainMostWork;
int64_t nTimeBestReceived = 0;
int nScriptCheckThreads = 0;
bool fImporting = false;
@ -398,6 +397,12 @@ CBlockIndex *CChain::FindFork(const CBlockLocator &locator) const {
return Genesis();
}
CBlockIndex *CChain::FindFork(CBlockIndex *pindex) const {
while (pindex && !Contains(pindex))
pindex = pindex->pprev;
return pindex;
}
CCoinsViewCache *pcoinsTip = NULL;
CBlockTreeDB *pblocktree = NULL;
@ -1890,6 +1895,11 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C
for (unsigned int i = 0; i < block.vtx.size(); i++)
g_signals.SyncTransaction(block.GetTxHash(i), block.vtx[i], &block);
// Watch for changes to the previous coinbase transaction.
static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.GetTxHash(0);
return true;
}
@ -2035,23 +2045,17 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew) {
return true;
}
// Make chainMostWork correspond to the chain with the most work in it, that isn't
// Return the tip of the chain with the most work in it, that isn't
// known to be invalid (it's however far from certain to be valid).
void static FindMostWorkChain() {
static CBlockIndex* FindMostWorkChain() {
do {
CBlockIndex *pindexNew = NULL;
// In case the current best is invalid, do not consider it.
while (chainMostWork.Tip() && (chainMostWork.Tip()->nStatus & BLOCK_FAILED_MASK)) {
setBlockIndexValid.erase(chainMostWork.Tip());
chainMostWork.SetTip(chainMostWork.Tip()->pprev);
}
do {
// Find the best candidate header.
{
std::set<CBlockIndex*, CBlockIndexWorkComparator>::reverse_iterator it = setBlockIndexValid.rbegin();
if (it == setBlockIndexValid.rend())
return;
return NULL;
pindexNew = *it;
}
@ -2075,70 +2079,111 @@ void static FindMostWorkChain() {
}
pindexTest = pindexTest->pprev;
}
if (fInvalidAncestor)
continue;
break;
if (!fInvalidAncestor)
return pindexNew;
} while(true);
// Check whether it's actually an improvement.
if (chainMostWork.Tip() && !CBlockIndexWorkComparator()(chainMostWork.Tip(), pindexNew))
return;
// We have a new best.
chainMostWork.SetTip(pindexNew);
}
// Try to activate to the most-work chain (thereby connecting it).
bool ActivateBestChain(CValidationState &state) {
LOCK(cs_main);
// Try to make some progress towards making pindexMostWork the active block.
static bool ActivateBestChainStep(CValidationState &state, CBlockIndex *pindexMostWork) {
AssertLockHeld(cs_main);
bool fInvalidFound = false;
CBlockIndex *pindexOldTip = chainActive.Tip();
bool fComplete = false;
while (!fComplete) {
FindMostWorkChain();
fComplete = true;
// Check whether we have something to do.
if (chainMostWork.Tip() == NULL) break;
CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
// Disconnect active blocks which are no longer in the best chain.
while (chainActive.Tip() && !chainMostWork.Contains(chainActive.Tip())) {
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
if (!DisconnectTip(state))
return false;
}
// Build list of new blocks to connect.
std::vector<CBlockIndex*> vpindexToConnect;
vpindexToConnect.reserve(pindexMostWork->nHeight - (pindexFork ? pindexFork->nHeight : -1));
while (pindexMostWork && pindexMostWork != pindexFork) {
vpindexToConnect.push_back(pindexMostWork);
pindexMostWork = pindexMostWork->pprev;
}
// Connect new blocks.
while (!chainActive.Contains(chainMostWork.Tip())) {
CBlockIndex *pindexConnect = chainMostWork[chainActive.Height() + 1];
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
if (!ConnectTip(state, pindexConnect)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
InvalidChainFound(chainMostWork.Tip());
fComplete = false;
InvalidChainFound(vpindexToConnect.back());
state = CValidationState();
fInvalidFound = true;
break;
} else {
// A system error occurred (disk space, database error, ...).
return false;
}
} else {
if (!pindexOldTip || chainActive.Tip()->nChainWork > pindexOldTip->nChainWork) {
// We're in a better position than we were. Return temporarily to release the lock.
break;
}
}
}
if (chainActive.Tip() != pindexOldTip) {
std::string strCmd = GetArg("-blocknotify", "");
if (!IsInitialBlockDownload() && !strCmd.empty())
// Callbacks/notifications for a new best chain.
if (fInvalidFound)
CheckForkWarningConditionsOnNewFork(vpindexToConnect.back());
else
CheckForkWarningConditions();
if (!pblocktree->Flush())
return state.Abort(_("Failed to sync block index"));
return true;
}
bool ActivateBestChain(CValidationState &state) {
CBlockIndex *pindexNewTip = NULL;
CBlockIndex *pindexMostWork = NULL;
do {
boost::this_thread::interruption_point();
bool fInitialDownload;
{
boost::replace_all(strCmd, "%s", chainActive.Tip()->GetBlockHash().GetHex());
LOCK(cs_main);
pindexMostWork = FindMostWorkChain();
// Whether we have anything to do at all.
if (pindexMostWork == NULL || pindexMostWork == chainActive.Tip())
return true;
if (!ActivateBestChainStep(state, pindexMostWork))
return false;
pindexNewTip = chainActive.Tip();
fInitialDownload = IsInitialBlockDownload();
}
// When we reach this point, we switched to a new tip (stored in pindexNewTip).
// Notifications/callbacks that can run without cs_main
if (!fInitialDownload) {
uint256 hashNewTip = pindexNewTip->GetBlockHash();
// Relay inventory, but don't relay old inventory during initial block download.
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
pnode->PushInventory(CInv(MSG_BLOCK, hashNewTip));
std::string strCmd = GetArg("-blocknotify", "");
if (!strCmd.empty()) {
boost::replace_all(strCmd, "%s", hashNewTip.GetHex());
boost::thread t(runCommand, strCmd); // thread runs free
}
}
uiInterface.NotifyBlocksChanged();
} while(pindexMostWork != chainActive.Tip());
return true;
}
CBlockIndex* AddToBlockIndex(CBlockHeader& block)
{
// Check for duplicate
@ -2198,26 +2243,6 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
if (!pblocktree->WriteBlockIndex(CDiskBlockIndex(pindexNew)))
return state.Abort(_("Failed to write block index"));
// New best?
if (!ActivateBestChain(state))
return false;
LOCK(cs_main);
if (pindexNew == chainActive.Tip())
{
// Clear fork warning if its no longer applicable
CheckForkWarningConditions();
// Notify UI to display prev block's coinbase if it was ours
static uint256 hashPrevBestCoinBase;
g_signals.UpdatedTransaction(hashPrevBestCoinBase);
hashPrevBestCoinBase = block.GetTxHash(0);
} else
CheckForkWarningConditionsOnNewFork(pindexNew);
if (!pblocktree->Flush())
return state.Abort(_("Failed to sync block index"));
uiInterface.NotifyBlocksChanged();
return true;
}
@ -2494,7 +2519,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
}
int nHeight = pindex->nHeight;
uint256 hash = pindex->GetBlockHash();
// Check that all transactions are finalized
BOOST_FOREACH(const CTransaction& tx, block.vtx)
@ -2538,16 +2562,6 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
return state.Abort(_("System error: ") + e.what());
}
// Relay inventory, but don't relay old inventory during initial block download
int nBlockEstimate = Checkpoints::GetTotalBlocksEstimate();
if (chainActive.Tip()->GetBlockHash() == hash)
{
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
if (chainActive.Height() > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : nBlockEstimate))
pnode->PushInventory(CInv(MSG_BLOCK, hash));
}
return true;
}
@ -2577,10 +2591,11 @@ void PushGetBlocks(CNode* pnode, CBlockIndex* pindexBegin, uint256 hashEnd)
bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
{
AssertLockHeld(cs_main);
// Check for duplicate
uint256 hash = pblock->GetHash();
{
LOCK(cs_main);
if (mapBlockIndex.count(hash))
return state.Invalid(error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString()), 0, "duplicate");
if (mapOrphanBlocks.count(hash))
@ -2649,7 +2664,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl
mapOrphanBlocksByPrev.erase(hashPrev);
}
LogPrintf("ProcessBlock: ACCEPTED\n");
}
if (!ActivateBestChain(state))
return error("ProcessBlock() : ActivateBestChain failed");
return true;
}
@ -3085,6 +3104,8 @@ bool InitBlockIndex() {
CBlockIndex *pindex = AddToBlockIndex(block);
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("LoadBlockIndex() : genesis block not accepted");
if (!ActivateBestChain(state))
return error("LoadBlockIndex() : genesis block cannot be activated");
} catch(std::runtime_error &e) {
return error("LoadBlockIndex() : failed to initialize block database: %s", e.what());
}
@ -3214,7 +3235,6 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
// process block
if (nBlockPos >= nStartByte) {
LOCK(cs_main);
if (dbp)
dbp->nPos = nBlockPos;
CValidationState state;
@ -3903,10 +3923,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
CInv inv(MSG_BLOCK, block.GetHash());
pfrom->AddInventoryKnown(inv);
{
LOCK(cs_main);
// Remember who we got this block from.
mapBlockSource[inv.hash] = pfrom->GetId();
MarkBlockAsReceived(inv.hash, pfrom->GetId());
}
CValidationState state;
ProcessBlock(state, pfrom, &block);

6
src/main.h

@ -1079,14 +1079,14 @@ public:
/** Find the last common block between this chain and a locator. */
CBlockIndex *FindFork(const CBlockLocator &locator) const;
/** Find the last common block between this chain and a block index entry. */
CBlockIndex *FindFork(CBlockIndex *pindex) const;
};
/** The currently-connected chain of blocks. */
extern CChain chainActive;
/** The currently best known chain of headers (some of which may be invalid). */
extern CChain chainMostWork;
/** Global variable that points to the active CCoinsView (protected by cs_main) */
extern CCoinsViewCache *pcoinsTip;

2
src/miner.cpp

@ -484,6 +484,7 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
LOCK(cs_main);
if (pblock->hashPrevBlock != chainActive.Tip()->GetBlockHash())
return error("BitcoinMiner : generated block is stale");
}
// Remove key from key pool
reservekey.KeepKey();
@ -498,7 +499,6 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey)
CValidationState state;
if (!ProcessBlock(state, NULL, pblock))
return error("BitcoinMiner : ProcessBlock, block not accepted");
}
return true;
}

2
src/rpcserver.cpp

@ -254,7 +254,7 @@ static const CRPCCommand vRPCCommands[] =
{ "getblocktemplate", &getblocktemplate, true, false, false },
{ "getmininginfo", &getmininginfo, true, false, false },
{ "getnetworkhashps", &getnetworkhashps, true, false, false },
{ "submitblock", &submitblock, false, false, false },
{ "submitblock", &submitblock, false, true, false },
/* Raw transactions */
{ "createrawtransaction", &createrawtransaction, false, false, false },

Loading…
Cancel
Save