personal_infra/ansible/roles/bitcoin_knots
counterweight d50774c39a
bitcoin-knots: raise dbcache from 200 to 1200
Tried on 2026-10-18 to cut the HDD reads: at 200 MB the P2P thread alone read
~4 MB/s validating relayed transactions. Steady-state reads did drop (to
~0.4 MB/s) and RPC rejections went to zero.

But block validation got SLOWER over the next 14 blocks: median 60s against
11s before. bitcoind's bench log puts all of it in input lookups at ~5 ms
each. The likely cause is that the extra GB came out of the guest's page
cache, which holds compressed chainstate files far more densely than
bitcoind's cache holds decoded coins. Committed because it is what is
running; probably to be reverted.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 22:10:25 +02:00
..
defaults bitcoin-knots: raise dbcache from 200 to 1200 2026-10-19 22:10:25 +02:00
handlers bitcoin-knots: convert to a role, de-Uptime-Kuma the health check 2026-09-13 18:13:40 +02:00
tasks uptime kuma: remove every live reference, repoint the probes to Gatus 2026-09-14 10:30:28 +02:00
templates bitcoin-knots: ride out block-time RPC stalls 2026-10-19 22:10:25 +02:00
README.md bitcoin-knots: convert to a role, de-Uptime-Kuma the health check 2026-09-13 18:13:40 +02:00

bitcoin_knots

Builds Bitcoin Knots from source with PGP + SHA256 verification of the release tarball, runs it as a full node on knots-box, and keeps a health check on a systemd timer. The second play in the calling playbook publishes the P2P port from the edge host via socket_proxy.

Converted from deploy_bitcoin_knots_playbook.yml (892 lines) under Plan 6. The playbook is now 40 lines.

The build is guarded; the chain is never touched

build.yml is 32 tasks, every one carrying when: not bitcoind_binary_exists.stat.exists. On a host that already has the binary the whole download / verify / 30-60 minute compile skips — including the two state: absent deletions, which target /opt/bitcoin-knots/source and the extracted build directory.

The chain lives elsewhere and nothing here touches it:

bitcoin_knots_dir /opt/bitcoin-knots — build tree, safe to delete
bitcoin_data_dir /var/lib/bitcoin — config, logs, wallets
bitcoin_large_data_dir /mnt/knots_data — ~875 GB of blockchain

The signature-verification tasks are the security control of this role. They are copied verbatim; do not "simplify" them.

⚠ This node is half of the mining setup

bitcoin.conf carries a DATUM Gateway section that was hand-added on the node and was missing from the playbook's template:

blockmaxsize=3985000
blockmaxweight=3985000
blocknotify=killall -USR1 datum_gateway
maxmempool=1000
blockreconstructionextratxn=1000000

blocknotify is how datum_gateway learns a new block landed. Running the old playbook would have deleted all of it, and solo mining would have carried on grinding against a stale template — a silent failure that costs money rather than raising an error. The template now carries it behind bitcoin_datum_gateway_enabled.

bitcoin-knots and datum-gateway are one system, not two services. Changing either config means thinking about both.

The restart handler, and why exactness matters now

The hand-written Restart bitcoind handler carried when: uptime_kuma_enabled | default(false), so it had been inert since the decommissioning: bitcoin.conf and the systemd unit both notify it and neither could restart anything. A config change applied to disk, reported success, and never took effect.

It is ungated here — which raises the bar for the template. Any residual difference between the template and the live file, down to a trailing newline, means the task reports changed and restarts a Bitcoin node on every run. It took four rounds of --check --diff to reach changed=0: the DATUM section, an explanatory comment that was rendering into the deployed file (now a {# #} Jinja comment), a # Pruning (optional) comment the live file had, and one trailing blank line.

dbcache

Computed as 90% of RAM unless bitcoin_dbcache_mb_override is set. The live node was hand-tuned to 200 MB; the calculation produces 3528. As with fulcrum, set_fact outranks role defaults, so the calculation honours the override — a value pinned only in defaults/ is silently ignored.

Monitoring: one variable, no product knowledge

The check tests bitcoind's RPC and records the answer in its exit code, which systemd keeps: systemctl is-failed bitcoin-knots-healthcheck.service. Set healthcheck_push_url to report anywhere that accepts an HTTP ping.

The timer had last fired 2026-08-09 while still reporting active and enabled — the same OnBootSec + OnUnitActiveSec dead chain as fulcrum, where nothing re-arms it if the service does not run in a given boot. The role runs the check once after enabling, which both smoke-tests it and supplies the reference the timer schedules from.