From 1b67479a4d83e6555462a03a1b7cccde94a8cfbd Mon Sep 17 00:00:00 2001 From: satoshi Date: Mon, 27 Apr 2026 21:26:50 +0300 Subject: [PATCH] Expose Block Broadcast Fallback config + plumb env through New advanced.block-broadcast-fallback union: * enabled (default: false) * grace-seconds (default: 30, range 10-600) * backup-rpcs: list of full bitcoind RPC URLs, with inline credentials supported (https://user:pass@host:port/). Up to 10. docker_entrypoint reads the list with yq, joins with newlines, and exports BACKUP_RPC_URLS plus PENDING_BLOCKS_DIR=/pending-blocks and PENDING_BLOCKS_GRACE so kamado-api's blocksubmit watcher activates. If the user enables the fallback but provides no URLs, we log a warning and disable rather than spam pending-block warnings. The companion ckpool patch (KamadoPool repo, 0004-dump-pending-block- for-fallback) writes raw block hex to PENDING_BLOCKS_DIR before each submit attempt and unlinks on success. The watcher only fires if ckpool's primary submit fails AND the operator configured backup RPCs. --- docker_entrypoint.sh | 24 +++++++++++++++++++ scripts/procedures/getConfig.ts | 42 +++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/docker_entrypoint.sh b/docker_entrypoint.sh index e3ec40e..67ff61f 100755 --- a/docker_entrypoint.sh +++ b/docker_entrypoint.sh @@ -63,6 +63,30 @@ else fi export MEMPOOL_BASE_URL +# Block-broadcast fallback: if the user enabled the safety-net +# broadcaster AND provided at least one backup RPC URL, point +# kamado-api at the patched-ckpool sidecar dir and feed the URL list +# through. Empty PENDING_BLOCKS_DIR disables the watcher entirely. +FALLBACK_ENABLED=$(q '.advanced.block-broadcast-fallback.enabled // false') +if [[ "${FALLBACK_ENABLED}" == "true" ]]; then + # Newline-joined list — matches kamado-api's parser. q strips + # quotes via -r, and yq emits one entry per line for [] expansion. + BACKUP_RPC_URLS=$(q '.advanced.block-broadcast-fallback.backup-rpcs[]' 2>/dev/null || true) + if [[ -z "${BACKUP_RPC_URLS}" ]]; then + echo "Block-broadcast fallback enabled but no backup RPC URLs listed — disabling." >&2 + export PENDING_BLOCKS_DIR="" + export BACKUP_RPC_URLS="" + else + # ckpool's patch writes hex files to /pending-blocks. + export PENDING_BLOCKS_DIR="${LOGDIR}/pending-blocks" + export BACKUP_RPC_URLS + export PENDING_BLOCKS_GRACE=$(q '.advanced.block-broadcast-fallback.grace-seconds // 30')s + fi +else + export PENDING_BLOCKS_DIR="" + export BACKUP_RPC_URLS="" +fi + # CKPool-solo uses the worker's stratum username as the payout # address and refuses to authenticate workers whose username is not # a valid address on the active network. The conf `btcaddress` is diff --git a/scripts/procedures/getConfig.ts b/scripts/procedures/getConfig.ts index c5ce364..97300b6 100644 --- a/scripts/procedures/getConfig.ts +++ b/scripts/procedures/getConfig.ts @@ -213,6 +213,48 @@ export const getConfig: T.ExpectedExports.getConfig = compat.getConfig({ }, }, }, + "block-broadcast-fallback": { + "type": "object", + "name": "Block Broadcast Fallback", + "description": + "Safety net for the moment a share meets network difficulty. ckpool always submits the block to its primary bitcoind first; if that fails (bitcoind crashed, RPC saturated, peering broken), kamado-api re-broadcasts the raw block to one or more backup RPC URLs you list here. A block is only re-submitted if it hasn't been accepted within the grace window — well-behaved primaries are never disturbed.", + "spec": { + "enabled": { + "type": "boolean", + "name": "Enable fallback broadcaster", + "description": + "Off by default. Turning on requires at least one Backup RPC URL — without one we'd just log warnings about pending blocks we can't help with.", + "default": false, + }, + "grace-seconds": { + "type": "number", + "name": "Grace period (seconds)", + "description": + "How long a block waits before kamado-api considers ckpool's submission attempt failed and broadcasts via fallback. 30s gives ckpool's own retry loop room to succeed against the primary.", + "nullable": false, + "range": "[10,600]", + "integral": true, + "units": "seconds", + "default": 30, + }, + "backup-rpcs": { + "type": "list", + "name": "Backup Bitcoin RPC URLs", + "description": + "Each entry is a full bitcoind RPC URL, optionally with credentials inline (https://user:pass@host:8332/). Used in order. Anything that speaks the standard JSON-RPC submitblock method works — a second self-hosted bitcoind, an authenticated public RPC service (Quicknode, GetBlock.io, Allnodes, etc.), or a peer node you trust. Leaving this empty disables the broadcaster.", + "subtype": "string", + "spec": { + "pattern": "^https?://[^\\s]+$", + "pattern-description": + "Must be an http:// or https:// URL with no whitespace.", + "masked": false, + "copyable": false, + }, + "default": [], + "range": "[0,10]", + }, + }, + }, }, }, });