I ran into this writing a regression test; it is a weird edge case with the headers-first logic.
The setup:
Create a 200-block blockchain with blocks that have ‘old’ timestamps (see https://github.com/gavinandresen/bitcoin-git/tree/chainalerts for code to do that)
Start up two nodes, both of which read in that 200-block chain. Connect node_b to node_a. Have node_b generate a new block. RESULT: node_a ignores it.
Here’s -debug=net output from node_b:
0UpdateTip: new best=00004900679d6cfbac61afa36cd6fda7f27af0e69e909373b947567d6dcc1d74 height=201
1sending: inv (37 bytes) peer=1
2received: getheaders (645 bytes) peer=1
3getheaders 201 to 00004900679d6cfbac61afa36cd6fda7f27af0e69e909373b947567d6dcc1d74 from peer=1
4sending: headers (82 bytes) peer=1
and from node_a:
0getheaders 200 to 0000000000000000000000000000000000000000000000000000000000000000 from peer=1
1got inv: block 00004900679d6cfbac61afa36cd6fda7f27af0e69e909373b947567d6dcc1d74 new peer=1
2received: headers (82 bytes) peer=1
I think the bug is because since both nodes just started up and read blocks from disk, pindexLastCommonBlock is NULL – it should be block 200. I think.
0(lldb) p state
1(<anonymous>::CNodeState) $60 = {
2 nMisbehavior = 0
3 fShouldBan = false
4 name = "127.0.0.1:59518"
5 rejects = size=0 {}
6 pindexBestKnownBlock = 0x0000000105122e10
7 hashLastUnknownBlock = {
8 base_uint<256> = {
9 pn = ([0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0, [5] = 0, [6] = 0, [7] = 0)
10 }
11 }
12 pindexLastCommonBlock = 0x0000000000000000
13 fSyncStarted = false
14 nStallingSince = 0
15 vBlocksInFlight = size=0 {}
16 nBlocksInFlight = 0
17}
Anyway, fFetch is never set to true on line 4422:
-> 4422 bool fFetch = !pto->fInbound || (pindexBestHeader && (state.pindexLastCommonBlock ? state.pindexLastCommonBlock->nHeight : 0) + 144 > pindexBestHeader->nHeight);
… because state.pindexLastCommonBlock is NULL, and 0+144 < 201
Writing this all down… would it make sense to fix this by always fetching when state.pindexLastCommonBlock is NULL ?