Skip to content

fix: fetch blocks over bitcoind's whitelisted p2p listener (0.11.1:14) - #77

Merged
MattDHill merged 2 commits into
masterfrom
fix/whitelisted-p2p-host
Jul 25, 2026
Merged

fix: fetch blocks over bitcoind's whitelisted p2p listener (0.11.1:14)#77
MattDHill merged 2 commits into
masterfrom
fix/whitelisted-p2p-host

Conversation

@helix-nine

Copy link
Copy Markdown

Problem

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 resolved 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:

subver: /electrs:0.11.1/   addrbind: 10.0.3.226:58333   permissions: []

Without noban/download, bitcoind can evict that connection to seat another peer, or cut it off under maxuploadtarget when it serves historical blocks. Electrs does not reconnect p2p — p2p_loop exiting drops new_block_send and 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 the new_block_rx arm of the select!, logs disconnected from bitcoind and exits 0 — which the SDK treats as a clean exit. With a client attached, server_rx is also ready, so it can instead handle the RPC (logging the get_history failure) and then hit rpc.sync(), which errors and exits 1daemon crashed → restart. That is why this reproduces only when something like Canary is running, polling unsubscribed scripthashes every 60s.

Change

Resolve bitcoind's peer-local host instead — a bridge-only binding onto its whitebind listener, granting noban + download. Requires bitcoind >=28.4:17.

After:

subver: /electrs:0.11.1/   addrbind: 10.0.3.47:58334   permissions: [noban, relay, mempool, download, addr]

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 export peerLocalHostId/peerPortLocal. The pin needs refreshing once it does.

Supersedes #76 — its corrections to the bitcoindBridge paragraph are folded into the rewrite here.

Test plan

  1. Update bitcoind to >=28.4:17 (Core 28.4:17/29.4:4/30.3:4/31.1:4, or Knots #knots:29.3.1:16), then install this build.
  2. Confirm the p2p address moved: start-cli package attach electrs -n electrs -- cat /data/electrs.tomldaemon_p2p_addr ends :58334.
  3. Confirm the peer is whitelisted:
    start-cli package attach bitcoind -n bitcoind -- bitcoin-cli -rpccookiefile=/root/.bitcoin/.cookie getpeerinfo | jq '.[]|select(.subver|test("electrs"))|{addrbind,permissions,conntime}'
  4. Install Canary, point it at Electrs, and let it sync several wallets for 10+ minutes. Electrs should not restart, and the peer's conntime should not change.
  5. Confirm the Electrum interface still serves clients normally (connect a wallet over ssl://<host>:50002).

Verified on a synced mainnet node: 3 concurrent clients replaying Canary's 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.

🤖 Generated with Claude Code

helix-nine and others added 2 commits July 25, 2026 10:16
… → 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
helix-nine force-pushed the fix/whitelisted-p2p-host branch from b0c9897 to b623ec5 Compare July 25, 2026 16:17

@MattDHill MattDHill left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@MattDHill
MattDHill merged commit c1699e9 into master Jul 25, 2026
3 checks passed
@MattDHill
MattDHill deleted the fix/whitelisted-p2p-host branch July 25, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants