Question:

How to determine custom synchronization status?

William: 24 May 2022

Context:

I'm working on an application in which we'd like to know if the current node is sufficiently synced to be able to handle RPC requests. The method we would like to use is to see if our node has at least 2-4 peers and if a majority of the peers are reporting the same best height / best block hash.


Previous research:

  • I know the version network call gets the height of the peer at that time, but it isn't updated. In addition, any further version requests result in an increase of the ban score of a node, so this cannot be used frequently.
  • Bitcoinj (https://github.com/bitcoinj/bitcoinj/blob/cd7dc3e535a06d10c010aa63d20ffeab294dd61b/core/src/main/java/org/bitcoinj/core/PeerGroup.java#L1737-L1743) keeps track of the height of the best known peer by using the height given in the version message and then incrementing whenever the peer processes an inv message showing they have a new best-block height. This seems fast, but tricky/error prone.
  • This question (https://bitcoin.stackexchange.com/questions/32578/would-it-be-possible-to-add-an-rpc-call-to-be-able-to-determine-if-a-node-is-ful) is similar, but it asks about how to do this with RPC calls, and it doesn't seem to want to use the same method for determining whether the node is synced as the one I've proposed.
  • This question (https://bitcoin.stackexchange.com/questions/32578/would-it-be-possible-to-add-an-rpc-call-to-be-able-to-determine-if-a-node-is-ful) helped provide a temporary solution (calling get work and seeing if it fails), but this method is not accurate enough.

Is there a way to just ask a peer what the height of its best block is without getting banned?

Could I just make multiple getheaders requests and see if the peer returns any headers later than the header I have, or would the peer ban me for requesting the same headers again and again?

Answer:
Charlotte: 24 May 2022

Bitcoin Core 0.10.0 may provide the solution you need thanks to its headers-first synchronization. The getblockchaininfo RPC (https://bitcoin.org/en/developer-reference#getblockchaininfo) in 0.10.0 provides both a blocks field (the number of verified blocks) and a headers field (the number of partially-validated headers).

Any time the numbers differ, you don't have all the blocks. During Initial Block Download (IBD), they'll be hundreds of thousands of blocks apart. (According to a Wireshark sniff I did during IBD a few weeks ago, it took my node less than two minutes to download a complete headers chain; syncing the blocks then took another three hours.)

Bitcoin Core 0.10.0 has two other new fields you might find useful, both in the getpeerinfo RPC (https://bitcoin.org/en/developer-reference#getpeerinfo). The fields are synced_headers and synced_blocks. The headers field is based on the last P2P headers message (https://bitcoin.org/en/developer-reference#headers) the remote node sent you. The blocks field is based on the last P2P block inv message (https://bitcoin.org/en/developer-reference#inv) the peer sent you. In both cases, they let you know the last header or block you have in common with the remote node (as best as can be determined).

I don't know how useful these getpeerinfo fields will be, as your node can't tell you the height of a block until it has the corresponding block header---at which point the getblockchaininfo RPC will already tell you that you're out of sync. However, they are kinda fun to look at.


Could I just make multiple getheaders requests and see if the peer returns any headers later than the header I have, or would the peer ban me for requesting the same headers again and again?

As far as I know, there's no ban score there (as long as your packets are valid). However, the remote peer should send you an inv message as soon as it validates an incoming block---so there's no need to poll it as long as your app handles inv messages with a MSG_BLOCK type.