diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 99 |
1 files changed, 66 insertions, 33 deletions
diff --git a/src/main.cpp b/src/main.cpp index 0ac23ab876..17fa765e8f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -128,6 +128,8 @@ namespace { }; map<uint256, pair<NodeId, list<QueuedBlock>::iterator> > mapBlocksInFlight; + // Number of preferrable block download peers. + int nPreferredDownload = 0; } // anon namespace ////////////////////////////////////////////////////////////////////////////// @@ -152,6 +154,8 @@ struct CMainSignals { boost::signals2::signal<void (const uint256 &)> Inventory; // Tells listeners to broadcast their data. boost::signals2::signal<void ()> Broadcast; + // Notifies listeners of a block validation result + boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked; } g_signals; } // anon namespace @@ -163,9 +167,11 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) { g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); + g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); } void UnregisterValidationInterface(CValidationInterface* pwalletIn) { + g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2)); g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn)); g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1)); g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); @@ -175,6 +181,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) { } void UnregisterAllValidationInterfaces() { + g_signals.BlockChecked.disconnect_all_slots(); g_signals.Broadcast.disconnect_all_slots(); g_signals.Inventory.disconnect_all_slots(); g_signals.SetBestChain.disconnect_all_slots(); @@ -225,6 +232,8 @@ struct CNodeState { int64_t nStallingSince; list<QueuedBlock> vBlocksInFlight; int nBlocksInFlight; + // Whether we consider this a preferred download peer. + bool fPreferredDownload; CNodeState() { nMisbehavior = 0; @@ -235,6 +244,7 @@ struct CNodeState { fSyncStarted = false; nStallingSince = 0; nBlocksInFlight = 0; + fPreferredDownload = false; } }; @@ -255,6 +265,16 @@ int GetHeight() return chainActive.Height(); } +void UpdatePreferredDownload(CNode* node, CNodeState* state) +{ + nPreferredDownload -= state->fPreferredDownload; + + // Whether this node should be marked as a preferred download node. + state->fPreferredDownload = (!node->fInbound || node->fWhitelisted) && !node->fOneShot && !node->fClient; + + nPreferredDownload += state->fPreferredDownload; +} + void InitializeNode(NodeId nodeid, const CNode *pnode) { LOCK(cs_main); CNodeState &state = mapNodeState.insert(std::make_pair(nodeid, CNodeState())).first->second; @@ -271,6 +291,7 @@ void FinalizeNode(NodeId nodeid) { BOOST_FOREACH(const QueuedBlock& entry, state->vBlocksInFlight) mapBlocksInFlight.erase(entry.hash); EraseOrphansFor(nodeid); + nPreferredDownload -= state->fPreferredDownload; mapNodeState.erase(nodeid); } @@ -1739,9 +1760,9 @@ bool ConnectBlock(CBlock& block, CValidationState& state, CBlockIndex* pindex, C } // Update the on-disk chain state. -bool static WriteChainState(CValidationState &state) { +bool static WriteChainState(CValidationState &state, bool forceWrite=false) { static int64_t nLastWrite = 0; - if (pcoinsTip->GetCacheSize() > nCoinCacheSize || (!IsInitialBlockDownload() && GetTimeMicros() > nLastWrite + 600*1000000)) { + if (forceWrite || pcoinsTip->GetCacheSize() > nCoinCacheSize || (!IsInitialBlockDownload() && GetTimeMicros() > nLastWrite + 600*1000000)) { // Typical CCoins structures on disk are around 100 bytes in size. // Pushing a new one to the database can cause it to be written // twice (once in the log, and once in the tables). This is already @@ -1864,7 +1885,9 @@ bool static ConnectTip(CValidationState &state, CBlockIndex *pindexNew, CBlock * { CCoinsViewCache view(pcoinsTip); CInv inv(MSG_BLOCK, pindexNew->GetBlockHash()); - if (!ConnectBlock(*pblock, state, pindexNew, view)) { + bool rv = ConnectBlock(*pblock, state, pindexNew, view); + g_signals.BlockChecked(*pblock, state); + if (!rv) { if (state.IsInvalid()) InvalidBlockFound(pindexNew, state); return error("ConnectTip() : ConnectBlock %s failed", pindexNew->GetBlockHash().ToString()); @@ -2257,6 +2280,8 @@ bool CheckBlock(const CBlock& block, CValidationState& state, bool fCheckPOW, bo { // These are checks that are independent of context. + // Check that the header is valid (particularly PoW). This is mostly + // redundant with the call in AcceptBlockHeader. if (!CheckBlockHeader(block, state, fCheckPOW)) return false; @@ -2328,6 +2353,9 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc return true; } + if (!CheckBlockHeader(block, state)) + return false; + // Get prev block index CBlockIndex* pindexPrev = NULL; int nHeight = 0; @@ -2504,7 +2532,7 @@ void CBlockIndex::BuildSkip() pskip = pprev->GetAncestor(GetSkipHeight(nHeight)); } -bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) +bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp) { // Preliminary checks bool checked = CheckBlock(*pblock, state); @@ -2513,7 +2541,7 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl LOCK(cs_main); MarkBlockAsReceived(pblock->GetHash()); if (!checked) { - return error("ProcessBlock() : CheckBlock FAILED"); + return error("%s : CheckBlock FAILED", __func__); } // Store to disk @@ -2523,11 +2551,11 @@ bool ProcessBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBl mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); } if (!ret) - return error("ProcessBlock() : AcceptBlock FAILED"); + return error("%s : AcceptBlock FAILED", __func__); } if (!ActivateBestChain(state, pblock)) - return error("ProcessBlock() : ActivateBestChain failed"); + return error("%s : ActivateBestChain failed", __func__); return true; } @@ -2999,6 +3027,8 @@ bool InitBlockIndex() { return error("LoadBlockIndex() : genesis block not accepted"); if (!ActivateBestChain(state, &block)) return error("LoadBlockIndex() : genesis block cannot be activated"); + // Force a chainstate write so that when we VerifyDB in a moment, it doesnt check stale data + return WriteChainState(state, true); } catch(std::runtime_error &e) { return error("LoadBlockIndex() : failed to initialize block database: %s", e.what()); } @@ -3134,12 +3164,14 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) } // process in case the block isn't known yet - if (mapBlockIndex.count(hash) == 0) { + if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) { CValidationState state; - if (ProcessBlock(state, NULL, &block, dbp)) + if (ProcessNewBlock(state, NULL, &block, dbp)) nLoaded++; if (state.IsError()) break; + } else if (hash != Params().HashGenesisBlock() && mapBlockIndex[hash]->nHeight % 1000 == 0) { + LogPrintf("Block Import: already had block %s at height %d\n", hash.ToString(), mapBlockIndex[hash]->nHeight); } // Recursively process earlier encountered successors of this block @@ -3156,7 +3188,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp) LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(), head.ToString()); CValidationState dummy; - if (ProcessBlock(dummy, NULL, &block, &it->second)) + if (ProcessNewBlock(dummy, NULL, &block, &it->second)) { nLoaded++; queue.push_back(block.GetHash()); @@ -3451,12 +3483,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, else pfrom->fRelayTxes = true; - if (pfrom->fInbound && addrMe.IsRoutable()) - { - pfrom->addrLocal = addrMe; - SeenLocal(addrMe); - } - // Disconnect if we connected to ourself if (nNonce == nLocalHostNonce && nNonce > 1) { @@ -3465,12 +3491,20 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, return true; } + pfrom->addrLocal = addrMe; + if (pfrom->fInbound && addrMe.IsRoutable()) + { + SeenLocal(addrMe); + } + // Be shy and don't send version until we hear if (pfrom->fInbound) pfrom->PushVersion(); pfrom->fClient = !(pfrom->nServices & NODE_NETWORK); + // Potentially mark this peer as a preferred download peer. + UpdatePreferredDownload(pfrom, State(pfrom->GetId())); // Change version pfrom->PushMessage("verack"); @@ -3483,7 +3517,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, { CAddress addr = GetLocalAddress(&pfrom->addr); if (addr.IsRoutable()) + { + pfrom->PushAddress(addr); + } else if (IsPeerAddrLocalGood(pfrom)) { + addr.SetIP(pfrom->addrLocal); pfrom->PushAddress(addr); + } } // Get recent addresses @@ -3934,7 +3973,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, pfrom->AddInventoryKnown(inv); CValidationState state; - ProcessBlock(state, pfrom, &block); + ProcessNewBlock(state, pfrom, &block); int nDoS; if (state.IsInvalid(nDoS)) { pfrom->PushMessage("reject", strCommand, state.GetRejectCode(), @@ -4346,24 +4385,18 @@ bool SendMessages(CNode* pto, bool fSendTrickle) static int64_t nLastRebroadcast; if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60)) { + LOCK(cs_vNodes); + BOOST_FOREACH(CNode* pnode, vNodes) { - LOCK(cs_vNodes); - BOOST_FOREACH(CNode* pnode, vNodes) - { - // Periodically clear setAddrKnown to allow refresh broadcasts - if (nLastRebroadcast) - pnode->setAddrKnown.clear(); + // Periodically clear setAddrKnown to allow refresh broadcasts + if (nLastRebroadcast) + pnode->setAddrKnown.clear(); - // Rebroadcast our address - if (fListen) - { - CAddress addr = GetLocalAddress(&pnode->addr); - if (addr.IsRoutable()) - pnode->PushAddress(addr); - } - } + // Rebroadcast our address + AdvertizeLocal(pnode); } - nLastRebroadcast = GetTime(); + if (!vNodes.empty()) + nLastRebroadcast = GetTime(); } // @@ -4415,7 +4448,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle) // Start block sync if (pindexBestHeader == NULL) pindexBestHeader = chainActive.Tip(); - bool fFetch = !pto->fInbound || (pindexBestHeader && (state.pindexLastCommonBlock ? state.pindexLastCommonBlock->nHeight : 0) + 144 > pindexBestHeader->nHeight); + bool fFetch = state.fPreferredDownload || (nPreferredDownload == 0 && !pto->fClient && !pto->fOneShot); // Download if this is a nice peer, or we have no nice peers and this one might do. if (!state.fSyncStarted && !pto->fClient && fFetch && !fImporting && !fReindex) { // Only actively request headers from a single peer, unless we're close to today. if (nSyncStarted == 0 || pindexBestHeader->GetBlockTime() > GetAdjustedTime() - 24 * 60 * 60) { |