fix: fetch blocks over bitcoind's whitelisted p2p listener (0.11.1:14) - #77
Merged
Conversation
helix-nine
force-pushed
the
fix/whitelisted-p2p-host
branch
from
July 25, 2026 16:03
7dd6045 to
b0c9897
Compare
… → 0.11.1:14 electrs pulls whole blocks over p2p — for the index, and again for every `blockchain.scripthash.get_history` on a scripthash the client never subscribed to. It was resolving bitcoind's `peer` host, which maps onto the plain `bind` that anonymous inbound peers share, so the connection earned no permissions (confirmed on a live node: `permissions: []`) and bitcoind could evict it or cut it off under `maxuploadtarget`. electrs does not reconnect p2p; `p2p_loop` exiting drops `new_block_send` and takes the process down by design. One drop is a restart — and under a client that polls unsubscribed scripthashes every 60s, such as Canary, a restart loop. Resolve bitcoind's `peer-local` host instead: a bridge-only binding onto its whitebind listener, granting noban + download. Requires bitcoind `>=28.4:17`. Verified on a synced mainnet node: 3 concurrent clients replaying that query pattern, 532 unsubscribed `get_history` calls returning 1.3M history entries and ~104 GB of block data over the peer connection — 0 errors, 0 dropped connections, peer `conntime` unchanged throughout, no electrs restart. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The `#next/28.x` pin string is unchanged; only the resolved commit in the lockfile moves, to the head that exports `peerLocalHostId`/`peerPortLocal`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
helix-nine
force-pushed
the
fix/whitelisted-p2p-host
branch
from
July 25, 2026 16:17
b0c9897 to
b623ec5
Compare
MattDHill
approved these changes
Jul 25, 2026
MattDHill
left a comment
There was a problem hiding this comment.
Reviewed by @MattDHill. Root cause and fix verified on a synced mainnet node: the peer moved from addrbind :58333 / permissions: [] to :58334 / [noban, relay, mempool, download, addr], and sustained 532 unsubscribed get_history queries (~104 GB of block data) with the connection never dropping and no electrs restart.
Depends on Start9Labs/bitcoin-core-startos#245 (merged); the #next/28.x pin has been fast-forwarded so this builds green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Electrs pulls whole blocks over p2p — for the index, and again for every
blockchain.scripthash.get_historyon a scripthash the client never subscribed to.It resolved bitcoind's
peerhost, which maps onto the plainbindthat anonymous inbound peers share, so the connection earned no permissions. Confirmed on a live node:Without
noban/download, bitcoind can evict that connection to seat another peer, or cut it off undermaxuploadtargetwhen it serves historical blocks. Electrs does not reconnect p2p —p2p_loopexiting dropsnew_block_sendand takes the process down by design (electrs/src/p2p.rs:255). One drop is a restart.Whether that surfaces as a crash loop depends on the client. In
server.rs, an idle electrs takes thenew_block_rxarm of theselect!, logsdisconnected from bitcoindand exits 0 — which the SDK treats as a clean exit. With a client attached,server_rxis also ready, so it can instead handle the RPC (logging theget_historyfailure) and then hitrpc.sync(), which errors and exits 1 →daemon crashed→ restart. That is why this reproduces only when something like Canary is running, polling unsubscribed scripthashes every 60s.Change
Resolve bitcoind's
peer-localhost instead — a bridge-only binding onto itswhitebindlistener, grantingnoban+download. Requires bitcoind>=28.4:17.After:
Depends on Start9Labs/bitcoin-core-startos#245 (and #246–#248) and Start9Labs/bitcoin-knots-startos#30–#31. CI will fail until those land: this package pins
bitcoin-core-startos#next/28.x, which doesn't yet exportpeerLocalHostId/peerPortLocal. The pin needs refreshing once it does.Supersedes #76 — its corrections to the
bitcoindBridgeparagraph are folded into the rewrite here.Test plan
>=28.4:17(Core28.4:17/29.4:4/30.3:4/31.1:4, or Knots#knots:29.3.1:16), then install this build.start-cli package attach electrs -n electrs -- cat /data/electrs.toml→daemon_p2p_addrends:58334.start-cli package attach bitcoind -n bitcoind -- bitcoin-cli -rpccookiefile=/root/.bitcoin/.cookie getpeerinfo | jq '.[]|select(.subver|test("electrs"))|{addrbind,permissions,conntime}'conntimeshould not change.ssl://<host>:50002).Verified on a synced mainnet node: 3 concurrent clients replaying Canary's query pattern — 532 unsubscribed
get_historycalls returning 1.3M history entries and ~104 GB of block data over the peer connection — 0 errors, 0 dropped connections, peerconntimeunchanged throughout, no electrs restart.🤖 Generated with Claude Code