Skip to content

docs(p2p): kubernetes P2P public exposure guide, document dht_mode off#1074

Merged
oskarszoon merged 4 commits into
bsv-blockchain:mainfrom
oskarszoon:fix/kube-docs
Jun 11, 2026
Merged

docs(p2p): kubernetes P2P public exposure guide, document dht_mode off#1074
oskarszoon merged 4 commits into
bsv-blockchain:mainfrom
oskarszoon:fix/kube-docs

Conversation

@oskarszoon

@oskarszoon oskarszoon commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

What

New howto: exposing the P2P service publicly on Kubernetes/AWS, plus fixes to the P2P settings reference and the p2p_port code default.

We ran into this on our own infra: exposing P2P on AWS requires an NLB with externalTrafficPolicy: Local. With the default Cluster policy, kube-proxy SNATs inbound connections, so peers appear to come from your own node IPs — this breaks libp2p's observed-address mechanism, peer bans, and source-IP diagnostics. None of this was documented.

Changes

  • docs/howto/miners/kubernetes/minersHowToExposeP2P.md (new)
    • NLB Service manifest (L4 required — ALB/classic ELB can't proxy raw libp2p streams); AWS Load Balancer Controller stated as prerequisite
    • externalTrafficPolicy: Local rationale + pod scheduling caveat
    • p2p_advertise_addresses pairing (NLB DNS name or EIP); multiaddr port is what peers dial — NLB listener must match
    • DHT mode selection (server/client/off) with resource implications; note that operator-managed deployments already default to server via the .operator context
    • How to join the BSVA DNS bootstrap pool (/dnsaddr/${network}.bootstrap.teranode.bsvb.tech) — requires public dialability + p2p_dht_mode = server
    • Reachability verification steps
  • docs/references/settings/services/p2p_settings.md
    • DHT section was missing p2p_dht_mode = off entirely (the settings.conf default — reference only documented server/client)
    • Hetzner/OVH abuse-flagging caveat promoted from settings.conf comment into the docs
    • DHTMode and BootstrapPeers table rows corrected
  • settings/settings.go + settings/p2p_settings.go: p2p_port code default corrected from 9906 to 9905. 9906 is the P2P gRPC/HTTP port; the collision would make a node advertise the HTTP port if it ever fell back to the code default. Struct tag longdesc fixed to match (it claimed 9906 was "the standard P2P port" while every multiaddr example in the same file uses 9905).
  • docs/P2P_NAT_TRAVERSAL.md: cloud/kubernetes best practice now links to the new howto
  • mkdocs.yml: new page registered under Miners → Configuration
  • docs/howto/developerSetup.md, docs/references/kafkaMessageFormat.md: fixed two pre-existing broken links so mkdocs build --strict passes clean

Verification

  • mkdocs build --strict: passes with zero warnings (was 2 pre-existing before this PR)
  • go build ./settings/... ./services/p2p/..., go vet ./settings/...: clean
  • go test ./settings/... ./services/asset/httpimpl/: pass (the settings handler test already asserted 9905)

Note: the DHTMode struct tag in settings/p2p_settings.go still says only "server"/"client" — left for a follow-up PR since it feeds the generated settings reference.

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

🤖 Claude Code Review

Status: Complete

Current Review: No blocking issues found. This is a well-scoped docs PR with one correct, minimal code fix.

Verified against the code:

  • p2p_port default 9906 → 9905 is correct. settings.conf ships P2P_PORT = 9905, while P2P_HTTP_PORT = 9906 — the old code default collided with the P2P HTTP port, so a fallback to the code default would have advertised the wrong port. New default matches settings.conf. No test asserts the old value; the remaining 9906 references (gRPC/HTTP/coinbase/alert) are correctly left unchanged.
  • Docs match settings.conf. p2p_dht_mode = off (default), p2p_dht_mode.operator = server, the /dnsaddr/${network}.bootstrap.teranode.bsvb.tech bootstrap pool, and the Hetzner/OVH abuse caveat all trace faithfully to the conf comments. The NLB / externalTrafficPolicy: Local guidance for source-IP preservation with libp2p is technically sound.
  • Links resolve. All relative paths in the new howto and the two broken-link fixes (developerSetup.md, kafkaMessageFormat.md) point at existing targets; consistent with the mkdocs build --strict claim.

Minor (already acknowledged in the PR description): the DHTMode struct tag in settings/p2p_settings.go still documents only server/client and feeds the settings portal via ExportMetadata, so the portal will not show the off option until the tag is updated. Fine to defer.

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Benchmark Comparison Report

Baseline: main (unknown)

Current: PR-1074 (7e2caaa)

Summary

  • Regressions: 0
  • Improvements: 0
  • Unchanged: 132
  • Significance level: p < 0.05
All benchmark results (sec/op)
Benchmark Baseline Current Change p-value
_NewBlockFromBytes-4 1.648µ 1.591µ ~ 0.200
SplitSyncedParentMap_SetIfNotExists/256_buckets-4 71.25n 70.98n ~ 0.200
SplitSyncedParentMap_SetIfNotExists/16_buckets-4 71.08n 71.46n ~ 0.100
SplitSyncedParentMap_SetIfNotExists/1_bucket-4 71.12n 70.84n ~ 0.100
SplitSyncedParentMap_ConcurrentSetIfNotExists/256_buckets... 32.84n 32.68n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/16_buckets_... 55.37n 55.52n ~ 0.700
SplitSyncedParentMap_ConcurrentSetIfNotExists/1_bucket_pa... 134.7n 128.3n ~ 0.100
MiningCandidate_Stringify_Short-4 219.9n 219.8n ~ 0.700
MiningCandidate_Stringify_Long-4 1.618µ 1.624µ ~ 0.100
MiningSolution_Stringify-4 846.8n 848.7n ~ 0.400
BlockInfo_MarshalJSON-4 1.757µ 1.775µ ~ 0.400
NewFromBytes-4 163.8n 135.5n ~ 0.700
AddTxBatchColumnar_Validation-4 2.574µ 2.594µ ~ 0.400
OffsetValidationLoop-4 544.5n 559.2n ~ 1.000
Mine_EasyDifficulty-4 66.20µ 65.91µ ~ 1.000
Mine_WithAddress-4 7.265µ 7.504µ ~ 0.400
DirectSubtreeAdd/4_per_subtree-4 66.33n 58.54n ~ 0.400
DirectSubtreeAdd/64_per_subtree-4 29.91n 30.16n ~ 0.400
DirectSubtreeAdd/256_per_subtree-4 28.92n 28.79n ~ 0.100
DirectSubtreeAdd/1024_per_subtree-4 27.79n 27.82n ~ 1.000
DirectSubtreeAdd/2048_per_subtree-4 27.53n 27.48n ~ 0.500
SubtreeProcessorAdd/4_per_subtree-4 240.5n 239.4n ~ 0.700
SubtreeProcessorAdd/64_per_subtree-4 235.5n 236.4n ~ 0.400
SubtreeProcessorAdd/256_per_subtree-4 237.1n 236.7n ~ 1.000
SubtreeProcessorAdd/1024_per_subtree-4 238.5n 233.0n ~ 1.000
SubtreeProcessorAdd/2048_per_subtree-4 228.7n 230.6n ~ 0.700
SubtreeProcessorRotate/4_per_subtree-4 230.8n 231.0n ~ 1.000
SubtreeProcessorRotate/64_per_subtree-4 232.0n 231.7n ~ 1.000
SubtreeProcessorRotate/256_per_subtree-4 230.2n 229.9n ~ 0.500
SubtreeProcessorRotate/1024_per_subtree-4 230.3n 228.9n ~ 0.200
SubtreeNodeAddOnly/4_per_subtree-4 54.04n 54.04n ~ 0.800
SubtreeNodeAddOnly/64_per_subtree-4 34.38n 34.19n ~ 0.700
SubtreeNodeAddOnly/256_per_subtree-4 33.41n 33.35n ~ 0.400
SubtreeNodeAddOnly/1024_per_subtree-4 32.66n 32.64n ~ 0.500
SubtreeCreationOnly/4_per_subtree-4 113.7n 112.7n ~ 0.200
SubtreeCreationOnly/64_per_subtree-4 395.0n 390.9n ~ 0.100
SubtreeCreationOnly/256_per_subtree-4 1.316µ 1.401µ ~ 0.100
SubtreeCreationOnly/1024_per_subtree-4 4.415µ 4.632µ ~ 0.100
SubtreeCreationOnly/2048_per_subtree-4 7.903µ 8.189µ ~ 0.100
SubtreeProcessorOverheadBreakdown/64_per_subtree-4 233.0n 229.0n ~ 0.100
SubtreeProcessorOverheadBreakdown/1024_per_subtree-4 232.6n 233.6n ~ 0.800
ParallelGetAndSetIfNotExists/1k_nodes-4 9.043m 12.310m ~ 0.100
ParallelGetAndSetIfNotExists/10k_nodes-4 12.96m 12.79m ~ 0.700
ParallelGetAndSetIfNotExists/50k_nodes-4 15.23m 16.84m ~ 0.100
ParallelGetAndSetIfNotExists/100k_nodes-4 18.23m 19.66m ~ 0.100
SequentialGetAndSetIfNotExists/1k_nodes-4 8.824m 8.948m ~ 0.100
SequentialGetAndSetIfNotExists/10k_nodes-4 12.79m 13.25m ~ 0.100
SequentialGetAndSetIfNotExists/50k_nodes-4 21.34m 22.92m ~ 0.200
SequentialGetAndSetIfNotExists/100k_nodes-4 26.55m 33.40m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/1k_nodes-4 10.37m 12.69m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/10k_nodes-4 15.59m 20.11m ~ 0.100
ProcessOwnBlockSubtreeNodesParallel/100k_nodes-4 20.21m 19.96m ~ 1.000
ProcessOwnBlockSubtreeNodesSequential/1k_nodes-4 11.78m 13.27m ~ 0.100
ProcessOwnBlockSubtreeNodesSequential/10k_nodes-4 18.05m 15.32m ~ 0.400
ProcessOwnBlockSubtreeNodesSequential/100k_nodes-4 50.00m 53.11m ~ 0.100
DiskTxMap_SetIfNotExists-4 3.462µ 3.423µ ~ 0.600
DiskTxMap_SetIfNotExists_Parallel-4 3.221µ 3.295µ ~ 0.700
DiskTxMap_ExistenceOnly-4 298.5n 299.3n ~ 1.000
Queue-4 187.0n 190.0n ~ 0.100
AtomicPointer-4 4.567n 4.574n ~ 1.000
TxMapSetIfNotExists-4 52.51n 52.39n ~ 0.400
TxMapSetIfNotExistsDuplicate-4 40.01n 39.92n ~ 0.700
ChannelSendReceive-4 579.7n 582.0n ~ 0.400
BlockAssembler_AddTx-4 0.02166n 0.02222n ~ 0.700
AddNode-4 8.716 8.934 ~ 0.700
AddNodeWithMap-4 9.088 9.272 ~ 0.400
CalcBlockWork-4 511.1n 476.5n ~ 0.400
CalculateWork-4 658.0n 656.4n ~ 1.000
CheckOldBlockIDs/on-chain-prefetch/1000-4 64.01µ 64.08µ ~ 1.000
CheckOldBlockIDs/off-chain-prefetch/1000-4 53.49µ 63.90µ ~ 0.700
CheckOldBlockIDs/on-chain-prefetch/10000-4 461.1µ 461.0µ ~ 0.700
CheckOldBlockIDs/off-chain-prefetch/10000-4 354.1µ 355.1µ ~ 1.000
BuildBlockLocatorString_Helpers/Size_10-4 1.350µ 1.344µ ~ 0.700
BuildBlockLocatorString_Helpers/Size_100-4 12.93µ 12.78µ ~ 0.100
BuildBlockLocatorString_Helpers/Size_1000-4 127.7µ 127.0µ ~ 0.700
CatchupWithHeaderCache-4 104.9m 104.7m ~ 0.100
SubtreeSizes/10k_tx_4_per_subtree-4 1.390m 1.368m ~ 0.700
SubtreeSizes/10k_tx_16_per_subtree-4 323.7µ 319.9µ ~ 0.400
SubtreeSizes/10k_tx_64_per_subtree-4 78.43µ 76.20µ ~ 0.200
SubtreeSizes/10k_tx_256_per_subtree-4 19.16µ 19.11µ ~ 0.400
SubtreeSizes/10k_tx_512_per_subtree-4 9.473µ 9.363µ ~ 0.200
SubtreeSizes/10k_tx_1024_per_subtree-4 4.712µ 4.690µ ~ 0.700
SubtreeSizes/10k_tx_2k_per_subtree-4 2.295µ 2.326µ ~ 0.100
BlockSizeScaling/10k_tx_64_per_subtree-4 74.09µ 75.51µ ~ 0.100
BlockSizeScaling/10k_tx_256_per_subtree-4 18.41µ 18.94µ ~ 0.100
BlockSizeScaling/10k_tx_1024_per_subtree-4 4.636µ 4.702µ ~ 0.400
BlockSizeScaling/50k_tx_64_per_subtree-4 386.4µ 398.6µ ~ 0.100
BlockSizeScaling/50k_tx_256_per_subtree-4 92.89µ 94.40µ ~ 0.100
BlockSizeScaling/50k_tx_1024_per_subtree-4 23.14µ 23.49µ ~ 0.400
SubtreeAllocations/small_subtrees_exists_check-4 160.1µ 158.4µ ~ 1.000
SubtreeAllocations/small_subtrees_data_fetch-4 164.5µ 166.8µ ~ 0.400
SubtreeAllocations/small_subtrees_full_validation-4 322.5µ 326.9µ ~ 0.700
SubtreeAllocations/medium_subtrees_exists_check-4 9.236µ 9.341µ ~ 1.000
SubtreeAllocations/medium_subtrees_data_fetch-4 9.672µ 9.766µ ~ 0.200
SubtreeAllocations/medium_subtrees_full_validation-4 18.84µ 19.07µ ~ 0.400
SubtreeAllocations/large_subtrees_exists_check-4 2.236µ 2.214µ ~ 0.400
SubtreeAllocations/large_subtrees_data_fetch-4 2.387µ 2.351µ ~ 0.200
SubtreeAllocations/large_subtrees_full_validation-4 4.745µ 4.695µ ~ 0.800
_BufferPoolAllocation/16KB-4 2.876µ 2.962µ ~ 0.400
_BufferPoolAllocation/32KB-4 5.483µ 7.373µ ~ 0.200
_BufferPoolAllocation/64KB-4 11.87µ 15.10µ ~ 0.100
_BufferPoolAllocation/128KB-4 22.98µ 22.78µ ~ 1.000
_BufferPoolAllocation/512KB-4 93.24µ 88.51µ ~ 0.100
_BufferPoolConcurrent/32KB-4 14.66µ 14.59µ ~ 1.000
_BufferPoolConcurrent/64KB-4 24.69µ 22.96µ ~ 0.100
_BufferPoolConcurrent/512KB-4 120.6µ 117.7µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/16KB-4 517.3µ 495.0µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/32KB-4 507.8µ 471.2µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/64KB-4 513.9µ 477.5µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/128KB-4 467.7µ 493.2µ ~ 0.100
_SubtreeDeserializationWithBufferSizes/512KB-4 480.4µ 494.0µ ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/16KB-4 28.70m 28.34m ~ 0.400
_SubtreeDataDeserializationWithBufferSizes/32KB-4 28.80m 28.28m ~ 0.200
_SubtreeDataDeserializationWithBufferSizes/64KB-4 28.50m 28.60m ~ 1.000
_SubtreeDataDeserializationWithBufferSizes/128KB-4 28.38m 28.12m ~ 0.700
_SubtreeDataDeserializationWithBufferSizes/512KB-4 27.96m 28.05m ~ 0.400
_PooledVsNonPooled/Pooled-4 649.3n 648.3n ~ 0.700
_PooledVsNonPooled/NonPooled-4 6.139µ 5.729µ ~ 0.100
_MemoryFootprint/Current_512KB_32concurrent-4 5.789µ 5.664µ ~ 0.400
_MemoryFootprint/Proposed_32KB_32concurrent-4 9.211µ 7.567µ ~ 0.100
_MemoryFootprint/Alternative_64KB_32concurrent-4 7.785µ 7.318µ ~ 0.100
_prepareTxsPerLevel-4 410.5m 417.6m ~ 0.400
_prepareTxsPerLevelOrdered-4 3.949m 3.660m ~ 0.400
_prepareTxsPerLevel_Comparison/Original-4 407.3m 407.7m ~ 0.100
_prepareTxsPerLevel_Comparison/Optimized-4 4.088m 3.745m ~ 0.100
StoreBlock_Sequential/BelowCSVHeight-4 338.6µ 329.7µ ~ 0.100
StoreBlock_Sequential/AboveCSVHeight-4 335.3µ 338.6µ ~ 0.400
GetUtxoHashes-4 257.3n 259.8n ~ 0.200
GetUtxoHashes_ManyOutputs-4 53.17µ 49.59µ ~ 0.100
_NewMetaDataFromBytes-4 224.9n 224.0n ~ 1.000
_Bytes-4 427.4n 444.3n ~ 0.100
_MetaBytes-4 141.8n 137.8n ~ 0.100

Threshold: >10% with p < 0.05 | Generated: 2026-06-11 15:11 UTC

@ordishs ordishs left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified every settings claim against the codebase — all accurate: p2p_dht_mode = off shipped default (settings.conf:838), code default "server" (settings/settings.go:501), the bootstrap pool / BSVA claims (settings.conf:801-806), the Hetzner/OVH caveat (settings.conf:826-837), and off is genuinely handled in the code path (services/p2p/Server.go:343-347). The k8s networking advice (L4 requirement, externalTrafficPolicy: Local to avoid kube-proxy SNAT breaking observed-address) is technically correct. All links and the mkdocs nav entry resolve.

Minor comments, none blocking:

  1. AWS LB Controller inconsistency: the example manifest uses aws-load-balancer-type: "external" + aws-load-balancer-nlb-target-type, which are AWS Load Balancer Controller annotations (the in-tree provider uses aws-load-balancer-type: nlb). The prose says target type ip "requires the AWS Load Balancer Controller", implying instance doesn't — but the manifest as written already requires it. Either state the controller as a prerequisite or switch the example to the in-tree annotation.
  2. Port wording: "default 9905" is the shipped settings.conf value (P2P_PORT = 9905); the code default is 9906 (settings/p2p_settings.go:18). Suggest the same "Go default vs settings.conf ships with" phrasing this PR already uses in the settings table.
  3. Operator context: p2p_dht_mode.operator = server (settings.conf:839) — since this is a Kubernetes guide and operator-managed deployments are the main k8s path, a footnote that the operator context already defaults to server would prevent confusion.
  4. selector: app: peer is deployment-specific; a one-liner telling readers to adapt it to their pod labels would help.
  5. Agree the struct tag fix (settings/p2p_settings.go:55) belongs in a separate PR — please open a tracking issue so it doesn't get lost.

…mode off

Add howto for exposing the P2P service publicly on Kubernetes/AWS:
NLB with externalTrafficPolicy: Local (required to preserve peer source
IPs for libp2p's observed-address mechanism and avoid cross-node
forwarding), advertise address configuration, DHT mode selection, and
how to join the BSVA DNS bootstrap pool.

Also fix the P2P settings reference, which omitted dht_mode "off"
(the settings.conf default) and the Hetzner/OVH abuse-flagging caveat
that previously existed only as a settings.conf comment.
- State AWS Load Balancer Controller as a prerequisite (the example
  annotations require it) and drop the misleading clause implying only
  target-type ip needs it
- Clarify the P2P port: multiaddrs in listen/advertise addresses are
  the source of truth; NLB listener must match the advertise multiaddr
- Note that operator-managed deployments already default to
  p2p_dht_mode=server via the .operator settings context
- Tell readers to adapt the selector to their pod labels
9906 is the P2P gRPC/HTTP port; the libp2p convention and shipped
settings.conf use 9905. The code default colliding with the HTTP port
would make a node advertise the wrong port if it ever fell back to it.
Also fixes the struct tag longdesc which claimed 9906 was the standard
P2P port while every multiaddr example in the same file uses 9905.
- developerSetup.md: kafka settings link had one ../ too many
- kafkaMessageFormat.md: wire.go link pointed outside the docs tree;
  mkdocs cannot resolve source files, keep it as a plain code reference
@sonarqubecloud

Copy link
Copy Markdown

@oskarszoon oskarszoon merged commit 74e64d8 into bsv-blockchain:main Jun 11, 2026
34 checks passed
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.

3 participants