diff options
| author | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-03 21:49:35 +0000 |
|---|---|---|
| committer | bitflash-maintainer <noreply@bitflash.invalid> | 2026-09-03 21:49:35 +0000 |
| commit | 944f93f163cb560f095556834b6eb75bfde60c9c (patch) | |
| tree | 11fd7dc0ccacb644a8b775d99795f656c4283da7 /src/net.h | |
| parent | 424da766b76ba572cc9a93c4dd03736dace04d80 (diff) | |
| parent | 42c840036f35a52beec27422d92457e7e530bdb1 (diff) | |
merge: !7 fix/block-fetch-failover into deploy/all-2026-08-24
Diffstat (limited to 'src/net.h')
| -rw-r--r-- | src/net.h | 45 |
1 files changed, 43 insertions, 2 deletions
| @@ -23,6 +23,12 @@ enum | |||
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | 25 | ||
| 26 | // Defined in main.cpp. True while this node is tracking the tip rather than | ||
| 27 | // still catching up, measured off the age of our own best block -- see there | ||
| 28 | // for why that and not a peer-reported height. Declared here because net.h is | ||
| 29 | // parsed before main.h and CNode::AskFor needs it. | ||
| 30 | bool IsBlockFetchNearTip(); | ||
| 31 | |||
| 26 | bool GetMyExternalIP(unsigned int& ipRet); | 32 | bool GetMyExternalIP(unsigned int& ipRet); |
| 27 | CNode* ConnectNodeBtf(const string& strBtfAddr); | 33 | CNode* ConnectNodeBtf(const string& strBtfAddr); |
| 28 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, | 34 | CNode* ConnectNodeBtfResolved(const string& strBtfAddr, const string& strMeeting, |
| @@ -89,6 +95,15 @@ static const int BTF_RECV_TIMEOUT_SECS = 30 * 60; | |||
| 89 | static const int BTF_SEND_STALL_SECS = 10 * 60; | 95 | static const int BTF_SEND_STALL_SECS = 10 * 60; |
| 90 | static const int BTF_HANDSHAKE_GRACE_SECS = 60; | 96 | static const int BTF_HANDSHAKE_GRACE_SECS = 60; |
| 91 | 97 | ||
| 98 | // How long a requested block gets before it is asked for again, in seconds. | ||
| 99 | // Used twice: CNode::AskFor spaces the queued per-announcer block retries this | ||
| 100 | // far apart instead of the two minutes transactions get, and the failover | ||
| 101 | // sweep in main.cpp re-issues a getdata to a different peer once a sent | ||
| 102 | // request has gone unanswered this long. A block body is at most 1 MB and | ||
| 103 | // somebody demonstrably has it -- they announced it -- so on this timescale | ||
| 104 | // "not here yet" means "not coming from that peer", not "still in transit". | ||
| 105 | static const int BLOCK_FETCH_RETRY_SECS = 15; | ||
| 106 | |||
| 92 | // A serialized object cannot be larger than MAX_SIZE, so no valid network | 107 | // A serialized object cannot be larger than MAX_SIZE, so no valid network |
| 93 | // message needs the old 256 MB header allowance. Keep the wire cap aligned with | 108 | // message needs the old 256 MB header allowance. Keep the wire cap aligned with |
| 94 | // what the deserializer can accept. How long a peer may sit on a partial | 109 | // what the deserializer can accept. How long a peer may sit on a partial |
| @@ -795,8 +810,34 @@ public: | |||
| 795 | static int64 nLastTime; | 810 | static int64 nLastTime; |
| 796 | nLastTime = nNow = max(nNow, ++nLastTime); | 811 | nLastTime = nNow = max(nNow, ++nLastTime); |
| 797 | 812 | ||
| 798 | // Each retry is 2 minutes after the last | 813 | // Each retry is 2 minutes after the last -- and because nRequestTime |
| 799 | nRequestTime = max(nRequestTime + 2 * 60 * 1000000, nNow); | 814 | // is shared across peers, the same spacing is what strings requests |
| 815 | // for one inv across its announcers. For transactions that is pacing; | ||
| 816 | // for a new block it was the stall of issue #33: nine peers announce | ||
| 817 | // the block, the first one asked does not serve it, and the ninth | ||
| 818 | // candidate is not even asked until sixteen minutes in, with the pool | ||
| 819 | // mining on the stale tip the whole time. | ||
| 820 | // | ||
| 821 | // Blocks retry on the fetch timescale, but only while we are at the | ||
| 822 | // tip. That is where the stall costs something -- the pool keeps | ||
| 823 | // handing out jobs against a dead tip -- and it is also where the | ||
| 824 | // spacing is nearly free: one block is in flight, and its body has | ||
| 825 | // almost always arrived before the second announcer's turn comes | ||
| 826 | // round, so AlreadyHave drops the duplicate before a getdata is sent. | ||
| 827 | // | ||
| 828 | // While catching up neither half holds. A peer working through a | ||
| 829 | // 500-deep queue can be minutes away from block N without anything | ||
| 830 | // being wrong, so at 15s the second announcer is asked at +15s, the | ||
| 831 | // third at +30s, and the bulk download arrives once per announcer -- | ||
| 832 | // up to eight times over. Nothing caps that: the eight-entry cap is on | ||
| 833 | // mapBlockFetch, which is a different mechanism from this spacing. | ||
| 834 | // Two minutes is the right number there, and it is what this line did | ||
| 835 | // before. Failover at the tip does not depend on this being 15s in any | ||
| 836 | // case: mapBlockFetch re-issues a stalled getdata to the next peer on | ||
| 837 | // its own timer, which is what actually fixes #33. | ||
| 838 | bool fFast = (inv.type == MSG_BLOCK && IsBlockFetchNearTip()); | ||
| 839 | int64 nRetryUsecs = (fFast ? BLOCK_FETCH_RETRY_SECS : 2 * 60) * 1000000LL; | ||
| 840 | nRequestTime = max(nRequestTime + nRetryUsecs, nNow); | ||
| 800 | mapAskFor.insert(make_pair(nRequestTime, inv)); | 841 | mapAskFor.insert(make_pair(nRequestTime, inv)); |
| 801 | } | 842 | } |
| 802 | 843 | ||