Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ item below is (or will be) written up in full in the in-development

### Changed

- `satd-init` (the reference stack, the appliance, Umbrel and StartOS) writes `rpcallowip=0.0.0.0/0`. The allowlist now gates the published TLS JSON-RPC listener too, and the stack-subnet list it wrote refused every client on the LAN before the handshake. The plain listener is kept off the LAN by the network, as the other plain listeners already were.
- `satd-init` (the reference stack, Umbrel and StartOS) writes `upgradechainstate=1` for a satd that has the flag, so an app-store node rebuilds its chainstate from the block files by itself on the first start after a release that changes the format, and restarts a rebuild a power cut interrupted.
- sat-tui draws the mempool size and UTXO age histograms as log-scaled bar charts, four rows tall with each bucket's count on its bar, instead of one-row linear sparklines that showed the largest bucket and flattened the rest. Both tails of each distribution are now visible. The age chart marks its young buckets as estimates while the node is still building its exact counts.
- **Storage: every index is keyed on a dense transaction ordinal instead of a 32-byte txid.** Four schema steps, 3 → 7, and **one** `-reindex-chainstate` for all of them; the block files are untouched and nothing is re-downloaded. A fully indexed mainnet chainstate is projected to drop from ~826 GB to ~449 GB. Pruned datadirs must resync. The four bullets below are the individual steps.
Expand Down
1 change: 0 additions & 1 deletion contrib/appliance/bin/satd-appliance
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ run_compose() {
# into /etc/default/satd, which is the only place satd will actually read it
# from: a `signet=1` line in a config file is accepted and then ignored.
render_config() {
SATD_STACK_SUBNET="$(stack_subnet)" \
SATD_TLS_HOSTNAME="$(hostname)" \
"$LIB/configure-network" "$1"
}
Expand Down
5 changes: 2 additions & 3 deletions contrib/appliance/files/compose.appliance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@
# SATD_HOST=10.77.0.1 docker compose \
# -f compose.appliance.yml -f compose.lightning.yml up -d
#
# satd itself binds 0.0.0.0 so the gateway reaches it. bitcoin.conf's
# rpcallowip limits that to this subnet, and nftables keeps every plain
# listener off the LAN entirely.
# satd itself binds 0.0.0.0 so the gateway reaches it, and nftables keeps
# every plain listener off the LAN: only this subnet reaches them.

name: satd-appliance

Expand Down
1 change: 0 additions & 1 deletion contrib/appliance/files/configure-network
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ SATD_MKCA="$LIB/mkca.sh" \
NETWORK="$NETWORK" \
SATD_MCP=1 \
SATD_STATUSPAGE=1 \
SATD_STACK_SUBNET="${SATD_STACK_SUBNET:-10.77.0.0/24}" \
SATD_TLS_HOSTNAME="${SATD_TLS_HOSTNAME:-$(hostname)}" \
SATD_CA_EXPORT_HINT="satd-appliance tls export-ca" \
"$LIB/satd-init"
Expand Down
3 changes: 1 addition & 2 deletions contrib/stack/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,5 @@ SATD_MCP=0
# echo "RTL_PASSWORD=$(openssl rand -hex 24)" >> .env

# --- internals --------------------------------------------------------------
# The compose network. Change only if it collides with an existing network;
# bitcoin.conf's rpcallowip is derived from it.
# The compose network. Change only if it collides with an existing network.
SATD_STACK_SUBNET=10.77.0.0/24
6 changes: 4 additions & 2 deletions contrib/stack/compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ services:
environment:
NETWORK: ${NETWORK:-signet}
SATD_MCP: ${SATD_MCP:-0}
# Read by the satd-init in images up to 0.6.0-rc1, which put the
# subnet in rpcallowip; later images ignore it.
SATD_STACK_SUBNET: ${SATD_STACK_SUBNET:-10.77.0.0/24}
SATD_TLS_HOSTNAME: ${SATD_TLS_HOSTNAME:-satd}
SATD_P2P_PORT: ${SATD_P2P_PORT:-38333}
Expand Down Expand Up @@ -104,8 +106,8 @@ volumes:

networks:
satd:
# A fixed subnet so bitcoin.conf's rpcallowip can name it exactly rather
# than opening RPC to every RFC1918 address.
# A fixed subnet: satd images up to 0.6.0-rc1 name it in rpcallowip
# (see satd-init above).
ipam:
config:
- subnet: ${SATD_STACK_SUBNET:-10.77.0.0/24}
2 changes: 0 additions & 2 deletions contrib/stack/satd/satd-init
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ TEMPLATE="${SATD_CONF_TEMPLATE:-/etc/satd/satd.conf.tmpl}"
MKCA="${SATD_MKCA:-/usr/local/bin/satd-mkca}"

NETWORK="${NETWORK:-signet}"
SUBNET="${SATD_STACK_SUBNET:-10.77.0.0/24}"
TLS_HOSTNAME="${SATD_TLS_HOSTNAME:-$(hostname)}"
MCP_ENABLED="${SATD_MCP:-0}"
# Further names to put in MCP's Host allowlist, comma-separated. The names
Expand Down Expand Up @@ -107,7 +106,6 @@ render() {
-e "s|@ESPLORA_TLS_PORT@|$ESPLORA_TLS_PORT|g" \
-e "s|@METRICS_PORT@|$METRICS_PORT|g" \
-e "s|@ZMQ_PORT@|$ZMQ_PORT|g" \
-e "s|@SUBNET@|$SUBNET|g" \
-e "s|@TLS_DIR@|$TLS_DIR|g" \
"$TEMPLATE"
}
Expand Down
15 changes: 10 additions & 5 deletions contrib/stack/satd/satd.conf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
# Plain listeners bind the compose network only and are NOT published to
# the host: RPC, Electrum, Esplora and the metrics endpoint are how the
# overlay containers (LND, NBXplorer, RTL, the mint) talk to satd, and
# those clients have no way to trust a private CA. `rpcallowip` narrows
# the RPC surface to this stack's own subnet.
# those clients have no way to trust a private CA. What keeps them inside
# is where they are reachable from, not `rpcallowip` (see JSON-RPC below).
#
# TLS listeners bind 0.0.0.0 and ARE published. Everything that leaves the
# host is TLS, presenting the per-install certificate from tls/mkca.sh.
Expand Down Expand Up @@ -55,9 +55,14 @@ peerblockfilters=1
server=1
rpcbind=0.0.0.0
rpcport=@RPC_PORT@
# The stack's own subnet, plus loopback for `docker exec satd sat-cli`.
rpcallowip=127.0.0.1
rpcallowip=@SUBNET@
# `rpcallowip` gates the TLS listener too, and that one is published: its
# clients are wherever the operator's wallets are, so the list admits every
# address. A narrower list refuses them before the TLS handshake. The plain
# listener is kept off the LAN by the network instead, as the other plain
# listeners already are: it is never published directly (StartOS fronts it
# with its own TLS proxy), and the appliance, which runs satd on the host,
# opens 8332 at nftables to the stack subnet only.
rpcallowip=0.0.0.0/0
rpctlsbind=0.0.0.0:@RPC_TLS_PORT@
rpctlscert=@TLS_DIR@/fullchain.crt
rpctlskey=@TLS_DIR@/leaf.key
Expand Down
14 changes: 13 additions & 1 deletion contrib/stack/tests/satd-init-test.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# satd-init's guarded keys (status page, metrics over TLS, chainstate
# upgrades), against stub binaries.
# upgrades) and the JSON-RPC allowlist, against stub binaries.
#
# Each must be written for a satd that has the key and not for one that does
# not: satd refuses an unknown config key, so the second case is the
Expand Down Expand Up @@ -79,6 +79,18 @@ else
ok "writes nothing for a satd without it"
fi

echo "== satd-init: JSON-RPC over TLS from the LAN =="
# rpcallowip gates the published TLS listener as well as the plain one, so a
# list naming only the stack subnet refuses every wallet on the LAN before the
# handshake. The appliance boot test sees that as an `unexpected eof`.
render "$WORK/new/satd" "$WORK/d" SATD_STACK_SUBNET=10.99.0.0/24
if grep -q '^rpctlsbind=0\.0\.0\.0:' "$WORK/d/bitcoin.conf" \
&& grep -qx 'rpcallowip=0.0.0.0/0' "$WORK/d/bitcoin.conf"; then
ok "the TLS listener admits a client outside the stack subnet"
else
bad "TLS RPC refuses the LAN: $(grep -E '^rpc(allowip|tlsbind)' "$WORK/d/bitcoin.conf" | tr '\n' ' ')"
fi

echo
[[ "$fail" -eq 0 ]] || { echo "satd-init-test.sh: FAILED"; exit 1; }
echo "satd-init-test.sh: all checks passed"
8 changes: 8 additions & 0 deletions docs/release-notes/0.6.0-pre.md
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,14 @@ only the clients of your plain-HTTP bind, add the TLS clients' addresses to
the same list before upgrading, or they will be refused. The same goes for
`-rpcreadonlytlsbind` and `-rpcreadonlyallowip`.

The reference stack, the appliance, and the Umbrel and StartOS packages were
that configuration: their TLS listener is published to the LAN, and their
allowlist named only the stack's own subnet. `satd-init` now writes
`rpcallowip=0.0.0.0/0`, and the plain listener is kept off the LAN by the
network instead (it is never published directly, and the appliance's
nftables admits only the stack subnet to it), as their other plain listeners
already were.

On a dual-stack bind (`[::]`), an IPv4 client is now matched as the IPv4
address it is. It reached the listener as `::ffff:a.b.c.d`, which matched no
IPv4 entry and missed the loopback exemption, so a plain `[::]` bind
Expand Down
Loading