diff options
| -rw-r--r-- | src/gui.cpp | 10 | ||||
| -rw-r--r-- | src/main.cpp | 8 | ||||
| -rw-r--r-- | src/net.cpp | 61 | ||||
| -rw-r--r-- | src/net.h | 42 |
4 files changed, 119 insertions, 2 deletions
diff --git a/src/gui.cpp b/src/gui.cpp index 825202b..28f5ffa 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -26,6 +26,7 @@ extern CAddress addrLocalHost; | |||
| 26 | 26 | ||
| 27 | void MainFrameRepaint(); | 27 | void MainFrameRepaint(); |
| 28 | int GetDiscoveredPeerCount(); | 28 | int GetDiscoveredPeerCount(); |
| 29 | int GetPeerMedianHeight(); | ||
| 29 | string DateTimeStr(int64 nTime); | 30 | string DateTimeStr(int64 nTime); |
| 30 | bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew); | 31 | bool SendMoney(CScript scriptPubKey, int64 nValue, CWalletTx& wtxNew); |
| 31 | int64 GetBalance(); | 32 | int64 GetBalance(); |
| @@ -238,6 +239,15 @@ static void DrawStatusBar() | |||
| 238 | connected, discovered, nBestHeight); | 239 | connected, discovered, nBestHeight); |
| 239 | } | 240 | } |
| 240 | 241 | ||
| 242 | // A node that has stopped receiving looks exactly like one with nothing to | ||
| 243 | // do. Now that peers announce their height, say the difference out loud | ||
| 244 | // instead of leaving the user to guess from a number that stopped moving. | ||
| 245 | int peerHeight = GetPeerMedianHeight(); | ||
| 246 | if (peerHeight >= 0 && nBestHeight < peerHeight - 1) | ||
| 247 | ImGui::TextColored(ImVec4(0.95f, 0.65f, 0.20f, 1.0f), | ||
| 248 | "Behind the network by %d block(s) -- peers report height %d", | ||
| 249 | peerHeight - nBestHeight, peerHeight); | ||
| 250 | |||
| 241 | ImGui::End(); | 251 | ImGui::End(); |
| 242 | } | 252 | } |
| 243 | 253 | ||
diff --git a/src/main.cpp b/src/main.cpp index c77448d..15805ca 100644 --- a/src/main.cpp +++ b/src/main.cpp | |||
| @@ -1884,6 +1884,12 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 1884 | if (pfrom->nVersion == 0) | 1884 | if (pfrom->nVersion == 0) |
| 1885 | return false; | 1885 | return false; |
| 1886 | 1886 | ||
| 1887 | // Optional: peers older than this field simply end the message here, | ||
| 1888 | // and nStartingHeight stays -1 for them. Never make this a requirement | ||
| 1889 | // -- every node released so far sends the short form. | ||
| 1890 | if (!vRecv.empty()) | ||
| 1891 | vRecv >> pfrom->nStartingHeight; | ||
| 1892 | |||
| 1887 | pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION)); | 1893 | pfrom->vSend.SetVersion(min(pfrom->nVersion, VERSION)); |
| 1888 | pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION)); | 1894 | pfrom->vRecv.SetVersion(min(pfrom->nVersion, VERSION)); |
| 1889 | 1895 | ||
| @@ -1912,7 +1918,7 @@ bool ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) | |||
| 1912 | if (!vPexOut.empty()) | 1918 | if (!vPexOut.empty()) |
| 1913 | pfrom->PushMessage("btfpeers", vPexOut); | 1919 | pfrom->PushMessage("btfpeers", vPexOut); |
| 1914 | 1920 | ||
| 1915 | if (LogAcceptsCategory("net")) printf("version addrMe = %s\n", addrMe.ToString().c_str()); | 1921 | if (LogAcceptsCategory("net")) printf("version addrMe = %s, peer height = %d\n", addrMe.ToString().c_str(), pfrom->nStartingHeight); |
| 1916 | } | 1922 | } |
| 1917 | 1923 | ||
| 1918 | 1924 | ||
diff --git a/src/net.cpp b/src/net.cpp index 81932d7..ac8df82 100644 --- a/src/net.cpp +++ b/src/net.cpp | |||
| @@ -1225,6 +1225,65 @@ void ThreadMessageHandler(void* parg) | |||
| 1225 | } | 1225 | } |
| 1226 | } | 1226 | } |
| 1227 | 1227 | ||
| 1228 | int GetPeerMedianHeight() | ||
| 1229 | { | ||
| 1230 | vector<int> vHeights; | ||
| 1231 | CRITICAL_BLOCK(cs_vNodes) | ||
| 1232 | foreach(CNode* pnode, vNodes) | ||
| 1233 | if (pnode->nStartingHeight >= 0) | ||
| 1234 | vHeights.push_back(pnode->nStartingHeight); | ||
| 1235 | |||
| 1236 | if (vHeights.empty()) | ||
| 1237 | return -1; | ||
| 1238 | |||
| 1239 | sort(vHeights.begin(), vHeights.end()); | ||
| 1240 | return vHeights[vHeights.size() / 2]; | ||
| 1241 | } | ||
| 1242 | |||
| 1243 | |||
| 1244 | // Say out loud when we are behind the network. | ||
| 1245 | // | ||
| 1246 | // This is the whole reason the height is in the handshake. Every serious bug | ||
| 1247 | // this node has had looked identical from the outside: running, threads alive, | ||
| 1248 | // nothing in the log, and no blocks arriving. A node that knows where everyone | ||
| 1249 | // else is can say so, and "8 blocks behind for 27 minutes" is a sentence a | ||
| 1250 | // user can act on. Deliberately not behind a debug category -- an operator who | ||
| 1251 | // already suspects trouble is not the one who needs telling. | ||
| 1252 | static void WarnIfBehind() | ||
| 1253 | { | ||
| 1254 | static int64 nLastWarned; | ||
| 1255 | static int64 nBehindSince; | ||
| 1256 | |||
| 1257 | int nPeers = GetPeerMedianHeight(); | ||
| 1258 | if (nPeers < 0 || nBestHeight < 0) | ||
| 1259 | return; | ||
| 1260 | |||
| 1261 | // One block of slack: somebody is always mid-relay. | ||
| 1262 | if (nBestHeight >= nPeers - 1) | ||
| 1263 | { | ||
| 1264 | nBehindSince = 0; | ||
| 1265 | return; | ||
| 1266 | } | ||
| 1267 | |||
| 1268 | int64 nNow = GetTime(); | ||
| 1269 | if (nBehindSince == 0) | ||
| 1270 | { | ||
| 1271 | nBehindSince = nNow; | ||
| 1272 | return; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | // Falling briefly behind is ordinary. Staying behind is not. | ||
| 1276 | if (nNow - nBehindSince < BTF_BEHIND_GRACE_SECS) | ||
| 1277 | return; | ||
| 1278 | if (nNow - nLastWarned < BTF_BEHIND_WARN_INTERVAL_SECS) | ||
| 1279 | return; | ||
| 1280 | |||
| 1281 | nLastWarned = nNow; | ||
| 1282 | printf("WARNING: %d blocks behind the network (height %d, peers report %d) for %d minutes\n", | ||
| 1283 | nPeers - nBestHeight, nBestHeight, nPeers, (int)((nNow - nBehindSince) / 60)); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | |||
| 1228 | void ThreadMessageHandler2(void* parg) | 1287 | void ThreadMessageHandler2(void* parg) |
| 1229 | { | 1288 | { |
| 1230 | printf("ThreadMessageHandler started\n"); | 1289 | printf("ThreadMessageHandler started\n"); |
| @@ -1250,6 +1309,8 @@ void ThreadMessageHandler2(void* parg) | |||
| 1250 | pnode->Release(); | 1309 | pnode->Release(); |
| 1251 | } | 1310 | } |
| 1252 | 1311 | ||
| 1312 | WarnIfBehind(); | ||
| 1313 | |||
| 1253 | // Wait and allow messages to bunch up | 1314 | // Wait and allow messages to bunch up |
| 1254 | vfThreadRunning[2] = false; | 1315 | vfThreadRunning[2] = false; |
| 1255 | Sleep(100); | 1316 | Sleep(100); |
| @@ -69,6 +69,21 @@ static const int BTF_HANDSHAKE_GRACE_SECS = 60; | |||
| 69 | // stay well under BTF_RECV_TIMEOUT_SECS. | 69 | // stay well under BTF_RECV_TIMEOUT_SECS. |
| 70 | static const int BTF_PING_INTERVAL_SECS = 10 * 60; | 70 | static const int BTF_PING_INTERVAL_SECS = 10 * 60; |
| 71 | 71 | ||
| 72 | // How long a node must stay behind the network before it says so, and how | ||
| 73 | // often it repeats itself. Five minutes is two and a half block intervals -- | ||
| 74 | // long enough that ordinary relay lag never trips it. | ||
| 75 | static const int BTF_BEHIND_GRACE_SECS = 5 * 60; | ||
| 76 | static const int BTF_BEHIND_WARN_INTERVAL_SECS = 5 * 60; | ||
| 77 | |||
| 78 | // Defined in main.cpp. Declared here because CNode announces it in the version | ||
| 79 | // message, and net.h is included before main.h. | ||
| 80 | extern int nBestHeight; | ||
| 81 | |||
| 82 | // Median height announced by the peers we are connected to, or -1 while nobody | ||
| 83 | // has told us anything. Median rather than maximum so one peer claiming an | ||
| 84 | // absurd height cannot move it. | ||
| 85 | int GetPeerMedianHeight(); | ||
| 86 | |||
| 72 | // Descriptors to hand a peer: ours first, then peers that answered us. | 87 | // Descriptors to hand a peer: ours first, then peers that answered us. |
| 73 | void BtfPexCollect(std::vector<std::string>& vDescOut); | 88 | void BtfPexCollect(std::vector<std::string>& vDescOut); |
| 74 | // Verify descriptors a peer sent and remember the good ones. Returns how many. | 89 | // Verify descriptors a peer sent and remember the good ones. Returns how many. |
| @@ -528,6 +543,11 @@ public: | |||
| 528 | int64 nLastRecv; | 543 | int64 nLastRecv; |
| 529 | int64 nLastSendEmpty; | 544 | int64 nLastSendEmpty; |
| 530 | 545 | ||
| 546 | // Height this peer announced in its version message, or -1 if it sent a | ||
| 547 | // version message that predates the field. Knowing how far along everyone | ||
| 548 | // else is, is the only way a node can tell "in sync" from "not hearing". | ||
| 549 | int nStartingHeight; | ||
| 550 | |||
| 531 | 551 | ||
| 532 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) | 552 | CNode(SOCKET hSocketIn, CAddress addrIn, bool fInboundIn=false) |
| 533 | { | 553 | { |
| @@ -549,12 +569,16 @@ public: | |||
| 549 | nLastSend = 0; | 569 | nLastSend = 0; |
| 550 | nLastRecv = 0; | 570 | nLastRecv = 0; |
| 551 | nLastSendEmpty = GetTime(); | 571 | nLastSendEmpty = GetTime(); |
| 572 | nStartingHeight = -1; | ||
| 552 | vfSubscribe.assign(256, false); | 573 | vfSubscribe.assign(256, false); |
| 553 | 574 | ||
| 554 | // Push a version message | 575 | // Push a version message |
| 555 | /// when NTP implemented, change to just nTime = GetAdjustedTime() | 576 | /// when NTP implemented, change to just nTime = GetAdjustedTime() |
| 556 | int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); | 577 | int64 nTime = (fInbound ? GetAdjustedTime() : GetTime()); |
| 557 | PushMessage("version", VERSION, nLocalServices, nTime, addr); | 578 | // nBestHeight goes last so a node that predates it stops reading after |
| 579 | // addr and treats the rest as trailing bytes, which cost it a log line | ||
| 580 | // and nothing else. | ||
| 581 | PushMessage("version", VERSION, nLocalServices, nTime, addr, nBestHeight); | ||
| 558 | } | 582 | } |
| 559 | 583 | ||
| 560 | ~CNode() | 584 | ~CNode() |
| @@ -771,6 +795,22 @@ public: | |||
| 771 | } | 795 | } |
| 772 | } | 796 | } |
| 773 | 797 | ||
| 798 | template<typename T1, typename T2, typename T3, typename T4, typename T5> | ||
| 799 | void PushMessage(const char* pszCommand, const T1& a1, const T2& a2, const T3& a3, const T4& a4, const T5& a5) | ||
| 800 | { | ||
| 801 | try | ||
| 802 | { | ||
| 803 | BeginMessage(pszCommand); | ||
| 804 | vSend << a1 << a2 << a3 << a4 << a5; | ||
| 805 | EndMessage(); | ||
| 806 | } | ||
| 807 | catch (...) | ||
| 808 | { | ||
| 809 | AbortMessage(); | ||
| 810 | throw; | ||
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 774 | 814 | ||
| 775 | void PushRequest(const char* pszCommand, | 815 | void PushRequest(const char* pszCommand, |
| 776 | void (*fn)(void*, CDataStream&), void* param1) | 816 | void (*fn)(void*, CDataStream&), void* param1) |