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)
0.10
Wladimir J. van der Laan 10 years ago
parent
commit
07b233a1b6
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 218
      src/main.cpp
  2. 6
      src/main.h
  3. 24
      src/miner.cpp
  4. 2
      src/rpcserver.cpp

218
src/main.cpp

@ -40,7 +40,6 @@ CTxMemPool mempool; @@ -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 { @@ -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 @@ -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) { @@ -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() {
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);
}
static CBlockIndex* FindMostWorkChain() {
do {
CBlockIndex *pindexNew = NULL;
// 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() { @@ -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;
CBlockIndex *pindexFork = chainActive.FindFork(pindexMostWork);
// Check whether we have something to do.
if (chainMostWork.Tip() == NULL) break;
// Disconnect active blocks which are no longer in the best chain.
while (chainActive.Tip() && chainActive.Tip() != pindexFork) {
if (!DisconnectTip(state))
return false;
}
// Disconnect active blocks which are no longer in the best chain.
while (chainActive.Tip() && !chainMostWork.Contains(chainActive.Tip())) {
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];
if (!ConnectTip(state, pindexConnect)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
InvalidChainFound(chainMostWork.Tip());
fComplete = false;
state = CValidationState();
break;
} else {
// A system error occurred (disk space, database error, ...).
return false;
}
// Connect new blocks.
BOOST_REVERSE_FOREACH(CBlockIndex *pindexConnect, vpindexToConnect) {
if (!ConnectTip(state, pindexConnect)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (!state.CorruptionPossible())
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());
boost::thread t(runCommand, strCmd); // thread runs free
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 @@ -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, @@ -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, @@ -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) @@ -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 @@ -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() { @@ -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) @@ -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) @@ -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());
{
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: @@ -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;

24
src/miner.cpp

@ -484,22 +484,22 @@ bool CheckWork(CBlock* pblock, CWallet& wallet, CReserveKey& reservekey) @@ -484,22 +484,22 @@ 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();
// Track how many getdata requests this block gets
{
LOCK(wallet.cs_wallet);
wallet.mapRequestCount[pblock->GetHash()] = 0;
}
// Remove key from key pool
reservekey.KeepKey();
// Process this block the same as if we had received it from another node
CValidationState state;
if (!ProcessBlock(state, NULL, pblock))
return error("BitcoinMiner : ProcessBlock, block not accepted");
// Track how many getdata requests this block gets
{
LOCK(wallet.cs_wallet);
wallet.mapRequestCount[pblock->GetHash()] = 0;
}
// Process this block the same as if we had received it from another node
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[] = @@ -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