Problem: During IBD, the node asks one peer at a time for the headers needed to catch up.
That peer can send valid empty headers, which the node accepts while still treating the peer as active, so no replacement is selected.
When no other preferred download peer is available, the headers timeout cannot release that peer either.
Fix: Stop treating the peer as active after an empty response while the best header is at least a day old, and clear its headers timeout.
Keep the time of the recent getheaders request so the same peer is not selected again immediately, while a later block announcement can still retry it.
If an outbound peer is already waiting to be disconnected because its chain is old, keep that check running after another peer takes over headers sync.
<details><summary>Manual reproducer</summary>
Both runs use the checked-out build/bin/bitcoind; Python only supplies two inbound P2P peers.
DATADIR="$(mktemp -d /tmp/bitcoin-empty-headers.XXXXXX)"
trap 'build/bin/bitcoin-cli -regtest -datadir="$DATADIR" -rpcport=18454 stop >/dev/null 2>&1; rm -rf "$DATADIR"' EXIT
{ cmake -B build && cmake --build build -j --target bitcoind bitcoin-cli; } >/dev/null 2>&1
build/bin/bitcoind -regtest -daemonwait -datadir="$DATADIR" -connect=0 -listen=1 -port=18455 -rpcport=18454
time python3 '/Users/lorinc/Library/Application Support/JetBrains/CLion2026.1/scratches/scratch_758.py'
killall bitcoind
The fixed node returns as soon as the replacement peer receives getheaders.
On the old node, that wait times out after 10 seconds because the initial peer is still treated as active.
</details>