Browse Source

Make sure we always have a node to do IBD from

This introduces the concept of the 'sync node', which is the one we
asked for missing blocks. In case the sync node goes away, a new one
will be selected.

For now, the heuristic is very simple, but it can easily be extended
later to add better policies.
miguelfreitas
Pieter Wuille 12 years ago
parent
commit
6ed71b5e4f
  1. 18
      src/main.cpp
  2. 59
      src/net.cpp
  3. 2
      src/net.h

18
src/main.cpp

@ -3235,18 +3235,6 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
} }
} }
// Ask the first connected node for block updates
static int nAskedForBlocks = 0;
if (!pfrom->fClient && !pfrom->fOneShot && !fImporting && !fReindex &&
(pfrom->nStartingHeight > (nBestHeight - 144)) &&
(pfrom->nVersion < NOBLKS_VERSION_START ||
pfrom->nVersion >= NOBLKS_VERSION_END) &&
(nAskedForBlocks < 1 || vNodes.size() <= 1))
{
nAskedForBlocks++;
pfrom->PushGetBlocks(pindexBest, uint256(0));
}
// Relay alerts // Relay alerts
{ {
LOCK(cs_mapAlerts); LOCK(cs_mapAlerts);
@ -3855,6 +3843,12 @@ bool SendMessages(CNode* pto, bool fSendTrickle)
pto->PushMessage("ping"); pto->PushMessage("ping");
} }
// Start block sync
if (pto->fStartSync && !fImporting && !fReindex) {
pto->fStartSync = false;
pto->PushGetBlocks(pindexBest, uint256(0));
}
// Resend wallet transactions that haven't gotten in a block yet // Resend wallet transactions that haven't gotten in a block yet
// Except during reindex, importing and IBD, when old wallet // Except during reindex, importing and IBD, when old wallet
// transactions become unconfirmed and spams other nodes. // transactions become unconfirmed and spams other nodes.

59
src/net.cpp

@ -44,6 +44,7 @@ static map<CNetAddr, LocalServiceInfo> mapLocalHost;
static bool vfReachable[NET_MAX] = {}; static bool vfReachable[NET_MAX] = {};
static bool vfLimited[NET_MAX] = {}; static bool vfLimited[NET_MAX] = {};
static CNode* pnodeLocalHost = NULL; static CNode* pnodeLocalHost = NULL;
static CNode* pnodeSync = NULL;
uint64 nLocalHostNonce = 0; uint64 nLocalHostNonce = 0;
static std::vector<SOCKET> vhListenSocket; static std::vector<SOCKET> vhListenSocket;
CAddrMan addrman; CAddrMan addrman;
@ -521,12 +522,16 @@ void CNode::CloseSocketDisconnect()
printf("disconnecting node %s\n", addrName.c_str()); printf("disconnecting node %s\n", addrName.c_str());
closesocket(hSocket); closesocket(hSocket);
hSocket = INVALID_SOCKET; hSocket = INVALID_SOCKET;
// in case this fails, we'll empty the recv buffer when the CNode is deleted
TRY_LOCK(cs_vRecvMsg, lockRecv);
if (lockRecv)
vRecvMsg.clear();
} }
// in case this fails, we'll empty the recv buffer when the CNode is deleted
TRY_LOCK(cs_vRecvMsg, lockRecv);
if (lockRecv)
vRecvMsg.clear();
// if this was the sync node, we'll need a new one
if (this == pnodeSync)
pnodeSync = NULL;
} }
void CNode::Cleanup() void CNode::Cleanup()
@ -1546,24 +1551,64 @@ bool OpenNetworkConnection(const CAddress& addrConnect, CSemaphoreGrant *grantOu
} }
// for now, use a very simple selection metric: the node from which we received
// most recently
double static NodeSyncScore(const CNode *pnode) {
return -pnode->nLastRecv;
}
void static StartSync(const vector<CNode*> &vNodes) {
CNode *pnodeNewSync = NULL;
double dBestScore = 0;
// fImporting and fReindex are accessed out of cs_main here, but only
// as an optimization - they are checked again in SendMessages.
if (fImporting || fReindex)
return;
// Iterate over all nodes
BOOST_FOREACH(CNode* pnode, vNodes) {
// check preconditions for allowing a sync
if (!pnode->fClient && !pnode->fOneShot &&
!pnode->fDisconnect && pnode->fSuccessfullyConnected &&
(pnode->nStartingHeight > (nBestHeight - 144)) &&
(pnode->nVersion < NOBLKS_VERSION_START || pnode->nVersion >= NOBLKS_VERSION_END)) {
// if ok, compare node's score with the best so far
double dScore = NodeSyncScore(pnode);
if (pnodeNewSync == NULL || dScore > dBestScore) {
pnodeNewSync = pnode;
dBestScore = dScore;
}
}
}
// if a new sync candidate was found, start sync!
if (pnodeNewSync) {
pnodeNewSync->fStartSync = true;
pnodeSync = pnodeNewSync;
}
}
void ThreadMessageHandler() void ThreadMessageHandler()
{ {
SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL); SetThreadPriority(THREAD_PRIORITY_BELOW_NORMAL);
while (true) while (true)
{ {
bool fHaveSyncNode = false;
vector<CNode*> vNodesCopy; vector<CNode*> vNodesCopy;
{ {
LOCK(cs_vNodes); LOCK(cs_vNodes);
vNodesCopy = vNodes; vNodesCopy = vNodes;
BOOST_FOREACH(CNode* pnode, vNodesCopy) BOOST_FOREACH(CNode* pnode, vNodesCopy) {
pnode->AddRef(); pnode->AddRef();
if (pnode == pnodeSync)
fHaveSyncNode = true;
}
} }
if (!fHaveSyncNode)
StartSync(vNodesCopy);
// Poll the connected nodes for messages // Poll the connected nodes for messages
CNode* pnodeTrickle = NULL; CNode* pnodeTrickle = NULL;
if (!vNodesCopy.empty()) if (!vNodesCopy.empty())

2
src/net.h

@ -202,6 +202,7 @@ public:
CBlockIndex* pindexLastGetBlocksBegin; CBlockIndex* pindexLastGetBlocksBegin;
uint256 hashLastGetBlocksEnd; uint256 hashLastGetBlocksEnd;
int nStartingHeight; int nStartingHeight;
bool fStartSync;
// flood relay // flood relay
std::vector<CAddress> vAddrToSend; std::vector<CAddress> vAddrToSend;
@ -242,6 +243,7 @@ public:
pindexLastGetBlocksBegin = 0; pindexLastGetBlocksBegin = 0;
hashLastGetBlocksEnd = 0; hashLastGetBlocksEnd = 0;
nStartingHeight = -1; nStartingHeight = -1;
fStartSync = false;
fGetAddr = false; fGetAddr = false;
nMisbehavior = 0; nMisbehavior = 0;
fRelayTxes = false; fRelayTxes = false;

Loading…
Cancel
Save