Skip to content

Commit 36692c9

Browse files
committed
Get rid of MAX_GETBLOCKTXN_DEPTH constant
Instead of allowing getblocktxn requests for the most recent 10 blocks (and ignoring requests for other blocks), allow getblocktxn requests for blocks more recent than the oldest outstanding cmpctblock message. This fixes a race condition that can happen during tests where more than 10 cmpctblock messages are sent to a peer before the first incoming getblocktxn messages can be processed, causing sync timeouts when the peer is not to be able to get in sync. This is an alternative to the fix in chaincodelabs/ccl-bitcoin@fix-8842-sync-timeouts Disadvantages of this implementation: - Requires a new state member. - Larger code change than the other fix. Advantages of this implementation: - Gets rid of the MAX_GETBLOCKTXN_DEPTH constant (which is just arbitrarily set at twice the value of MAX_CMPCTBLOCK_DEPTH). - Makes the protocol simpler and more deterministic from the perspective of receiving peers. Instead of getblocktxn responses yielding either blocktxn or block messages depending on timing and unrelated internal state of the sending node, valid getblocktxn requests will reliably trigger blocktxn responses and no other types of response. - Unlike the other fix, this doesn't require an update to BIP-152.
1 parent e1d1f57 commit 36692c9

File tree

3 files changed

+21
-10
lines changed

3 files changed

+21
-10
lines changed

qa/rpc-tests/p2p-compactblocks.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -589,12 +589,12 @@ def test_incorrect_blocktxn_response(self, node, test_node, version):
589589
assert_equal(int(node.getbestblockhash(), 16), block.sha256)
590590

591591
def test_getblocktxn_handler(self, node, test_node, version):
592-
# bitcoind won't respond for blocks whose height is more than 15 blocks
592+
# bitcoind won't respond for blocks whose height is more than 5 blocks
593593
# deep.
594-
MAX_GETBLOCKTXN_DEPTH = 10
594+
MAX_CMPCTBLOCK_DEPTH = 5
595595
chain_height = node.getblockcount()
596-
current_height = chain_height
597-
while (current_height >= chain_height - MAX_GETBLOCKTXN_DEPTH):
596+
current_height = chain_height - MAX_CMPCTBLOCK_DEPTH + 1
597+
while current_height <= chain_height:
598598
block_hash = node.getblockhash(current_height)
599599
block = FromHex(CBlock(), node.getblock(block_hash, False))
600600

@@ -621,10 +621,10 @@ def test_getblocktxn_handler(self, node, test_node, version):
621621
# Check that the witness matches
622622
assert_equal(tx.calc_sha256(True), block.vtx[index].calc_sha256(True))
623623
test_node.last_blocktxn = None
624-
current_height -= 1
624+
current_height += 1
625625

626626
# Next request should be ignored, as we're past the allowed depth.
627-
block_hash = node.getblockhash(current_height)
627+
block_hash = node.getblockhash(chain_height)
628628
msg.block_txn_request = BlockTransactionsRequest(int(block_hash, 16), [0])
629629
test_node.send_and_ping(msg)
630630
with mininode_lock:

src/main.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ struct CNodeState {
308308
* otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns.
309309
*/
310310
bool fSupportsDesiredCmpctVersion;
311+
int nGetblocktxnMinHeight;
311312

312313
CNodeState() {
313314
fCurrentlyConnected = false;
@@ -330,6 +331,7 @@ struct CNodeState {
330331
fHaveWitness = false;
331332
fWantsCmpctWitness = false;
332333
fSupportsDesiredCmpctVersion = false;
334+
nGetblocktxnMinHeight = std::numeric_limits<int>::max();
333335
}
334336
};
335337

@@ -4922,6 +4924,9 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
49224924
bool fPeerWantsWitness = State(pfrom->GetId())->fWantsCmpctWitness;
49234925
if (CanDirectFetch(consensusParams) && mi->second->nHeight >= chainActive.Height() - MAX_CMPCTBLOCK_DEPTH) {
49244926
CBlockHeaderAndShortTxIDs cmpctblock(block, fPeerWantsWitness);
4927+
if (State(pfrom->GetId())->nGetblocktxnMinHeight > mi->second->nHeight) {
4928+
State(pfrom->GetId())->nGetblocktxnMinHeight = mi->second->nHeight;
4929+
}
49254930
pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
49264931
} else
49274932
pfrom->PushMessageWithFlag(fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
@@ -5450,8 +5455,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
54505455
return true;
54515456
}
54525457

5453-
if (it->second->nHeight < chainActive.Height() - MAX_BLOCKTXN_DEPTH) {
5454-
LogPrint("net", "Peer %d sent us a getblocktxn for a block > %i deep", pfrom->id, MAX_BLOCKTXN_DEPTH);
5458+
if (it->second->nHeight < State(pfrom->GetId())->nGetblocktxnMinHeight) {
5459+
// If an older block is requested that this node didn't previously
5460+
// send a CMPCTBLOCK message for, just ignore the request instead
5461+
// of doing a potentially expensive block read.
5462+
LogPrint("net", "Peer %d sent us a getblocktxn for an out-of-bounds block.", pfrom->id);
54555463
return true;
54565464
}
54575465

@@ -5468,6 +5476,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
54685476
resp.txn[i] = block.vtx[req.indexes[i]];
54695477
}
54705478
pfrom->PushMessageWithFlag(State(pfrom->GetId())->fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
5479+
5480+
State(pfrom->GetId())->nGetblocktxnMinHeight = it->second->nHeight + 1;
54715481
}
54725482

54735483

@@ -6636,6 +6646,9 @@ bool SendMessages(CNode* pto, CConnman& connman)
66366646
CBlock block;
66376647
assert(ReadBlockFromDisk(block, pBestIndex, consensusParams));
66386648
CBlockHeaderAndShortTxIDs cmpctblock(block, state.fWantsCmpctWitness);
6649+
if (state.nGetblocktxnMinHeight > pBestIndex->nHeight) {
6650+
state.nGetblocktxnMinHeight = pBestIndex->nHeight;
6651+
}
66396652
pto->PushMessageWithFlag(state.fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
66406653
state.pindexBestHeaderSent = pBestIndex;
66416654
} else if (state.fPreferHeaders) {

src/main.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ static const unsigned int MAX_HEADERS_RESULTS = 2000;
9393
/** Maximum depth of blocks we're willing to serve as compact blocks to peers
9494
* when requested. For older blocks, a regular BLOCK response will be sent. */
9595
static const int MAX_CMPCTBLOCK_DEPTH = 5;
96-
/** Maximum depth of blocks we're willing to respond to GETBLOCKTXN requests for. */
97-
static const int MAX_BLOCKTXN_DEPTH = 10;
9896
/** Size of the "block download window": how far ahead of our current height do we fetch?
9997
* Larger windows tolerate larger download speed differences between peer, but increase the potential
10098
* degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning

0 commit comments

Comments
 (0)