• v0.3.5 731559c6ef

    agorise released this 2026-09-11 21:38:46 +00:00 | 10 commits to main since this release

    hidden-rpc v0.3.5

    Stop guessing from log text: watch the head block instead

    v0.3.4 decided whether a node was rebuilding its state or serving by grepping
    blurtd's log for replay progress lines. On a real node that grep came back empty at
    the wrong moment, so a node sitting at head block 1 — hours into a state rebuild
    — was reported as "Serving. head block 1".

    That was not just a cosmetic error. From "serving", the supervisor's next step is to
    remove the pinned --replay-blockchain flag, which would have stopped the rebuild
    and left a state at block 1 against a 63-million-block log. blurtd would then refuse
    to open with "does not match block log", crash-loop, be detected, and start another
    rebuild. Hours, on a loop, indefinitely.

    The decision no longer depends on log text at all. It uses the one fact that cannot
    be missed: is the head block moving? A serving node advances every three seconds.
    A node rebuilding its state answers with head block 1 and sits there. Two samples
    settle it, and the flag can only ever be removed from a node that has been seen
    advancing.

    Everything downstream got the same treatment: the rebuild is never interrupted, the
    wedged-node timer cannot fire during one, and both hidden-rpc-status and the
    installer now say "rebuilding its state by replaying the block_log" instead of
    computing a meaningless "63,559,304 blocks to go".

    Also: hidden-rpc-status no longer shows ? starting. The supervisor now runs its
    first node check before publishing a status file, so the first thing you read is
    what the node is actually doing.

    I broke I2P in v0.3.1, and this fixes it

    The low-power i2pd tuning added in v0.3.1 was appended to the end of
    /etc/i2pd/i2pd.conf. That file is an INI file: every key after a [section]
    header belongs to that section. So notransit = true at the end of the file became
    cpuext.notransit, and i2pd refused to start at all:

    unrecognised option 'cpuext.notransit'
    

    Verified against i2pd 2.49. On any node that took v0.3.1-v0.3.3, I2P has been down
    since that install
    — the .onion kept working, so it looked like a flaky tunnel.

    Fixed three ways:

    • the block is now inserted before the first section header, which is the only
      place global options work. Re-running the installer rewrites a misplaced block in
      the right place;
    • applying it is verified: the installer restarts i2pd and checks it actually
      came up. If it did not, the config is put back exactly as it was and you are told
      I2P is running on defaults instead;
    • the supervisor's deep repair now suspects our own changes first: if i2pd is
      down and our managed block is in its config, the block comes out and i2pd is
      restarted without it.

    An optimisation that stops a daemon starting is not an optimisation, and the code
    that adds one has to be able to take it back.

    A replaying node is no longer mistaken for a serving one

    During a block_log replay blurtd answers RPC with head block 1 and stays there for
    hours. v0.3.3 read that as "serving", which started the head-stall timer against a
    node doing exactly what it was told, and tried to strip the replay flag off a replay
    in progress (harmless — the rebuild refuses mid-replay — but it logged an alarming
    warning every minute for hours). The supervisor now checks whether a replay is
    running before calling a node serving, and hidden-rpc-status shows real replay
    progress instead of head block 1.

    A node that cannot open its own database now fixes itself

    On a real node, blurtd was exiting immediately on every start with:

    Chain state does not match block log. Please reindex blockchain.
    

    This is what a hard kill or a power cut leaves behind: blurtd's stored state and the
    block_log disagree, so it refuses to open, exits 1, the container restart policy
    starts it again, and it exits again — forever. Restarting it, rebuilding the
    container, rebooting the machine: none of them can ever help, because the state
    itself has to be rebuilt.

    Two things came out of it.

    A crash loop was being mistaken for a node hard at work. v0.3.2 decided a node
    was busy if its log kept moving — and a crash loop churns its log constantly while
    the container reports running. The supervisor now checks the container runtime's
    restart counter, which is the only thing that tells those two apart, before it
    looks at log activity.

    blurtd's own diagnosis is now read and acted on. It says exactly what is wrong
    and what the fix is, in plain English, in its log. When the supervisor sees that
    message it rebuilds the state by replaying the block_log once — hours, unattended —
    records that it did, and removes the replay flag again as soon as the node serves.
    It will not start a second replay on top of a running one, will not repeat it
    within 12 hours, and will not start one at all while maintenance mode is on.

    The installer handles it too: it reads the old container's log before removing it,
    so a re-run on an affected node starts the rebuild automatically and says what it is
    doing. There is also an explicit command:

    ./installer/hidden-rpc-setup.sh --reindex
    

    hidden-rpc-status reports it as "Rebuilding the chain state — its stored state did
    not match the block_log, so it is replaying once."

    Since v0.3.1: two judgement bugs found on a real node

    v0.3.1 installs and runs. Watching a node come up on real hardware showed two
    places where the supervisor was judging by a stopwatch instead of by evidence.

    1. A slow load could be mistaken for a hang. The node was considered "still
    loading" for a fixed 30 minutes and "stuck" after that. On a machine with a large
    chain on a slow disk, reading the state into memory can take longer — and the one
    mistake that makes things genuinely worse is restarting a node halfway through
    loading, because then it never finishes. The supervisor now asks the node instead:
    if blurtd's log keeps moving, it is working, and it is left alone however long it
    takes. It only acts when the node is running, silent, and not answering — both
    conditions, past both windows (NODE_STALL, default 30 min, and GRACE_NODE, now
    1 hour). hidden-rpc-status says which it is: "its log is still moving, so it is
    working — leave it alone"
    .

    2. Slow probes looked like waking from suspend. Resume detection timed the
    whole loop. But a tick in which both hidden-service self-dials time out
    legitimately takes PROBE_TIMEOUT_TOR + PROBE_TIMEOUT_I2P = 105 seconds, which
    tripped the "woke up" threshold — so an unreachable node forced a full re-check and
    reset its repair ladders on every single cycle. The check now measures the sleep
    only, which is immune to slow probes and still catches a real suspend. Verified: a
    tick spending 8 seconds in probes with a 2-second threshold now produces zero false
    wake-ups.

    Also in this release: the installer no longer holds your terminal for up to 30
    minutes waiting for a node to finish loading. It waits 5 minutes, then hands the
    prompt back and tells you to use hidden-rpc-status --watch — the self-healer is
    already watching the node by then, so there is nothing to sit and guard.


    If you tried v0.3.0: this is the fix

    v0.3.0 could not install. It stopped at "Starting your node" on every machine,
    with no useful explanation. My mistake, and an avoidable one.

    The installer loaded its shared repair library like this:

    DOCKER_CMD="$SUDO docker" . "$SUP_SRC/heal.sh"
    

    A variable assignment written in front of the . builtin is a temporary
    environment assignment: bash throws it away when the command finishes. While it
    was in effect, though, the library's own : "${DOCKER_CMD:=docker}" saw the name
    as already set and skipped its default — so DOCKER_CMD ended up unset, and
    every container command after that ran as timeout 120 run -d …, which fails
    instantly. The library's error went to /dev/null, so all you saw was "the node
    didn't start on this try".

    Fixed in three ways, so it cannot happen again in this shape or any other:

    • one load_heal_lib function does the loading with plain assignments, and
      verifies afterwards that the helpers exist and the command wrappers are
      non-empty — stopping with a clear message if not, before touching anything;
    • container failures now report what the container runtime actually said,
      instead of a shrug;
    • a third test suite, supervisor/tests/installer-lint.sh, runs the real
      start_node out of the real installer against a fake docker and asserts the
      exact command line it produces. That is the test that was missing: v0.3.0's
      supervisor was tested thoroughly and its installer was never executed at all.

    If v0.3.0 removed the container on your node before failing, nothing was lost —
    it was stopped gracefully first and the chain data lives in the Docker volume.
    Re-running the installer rebuilds the container and the node loads its state in
    the usual few minutes. No replay.

    Everything below is the v0.3.0 release, unchanged.


    A node that went down and stayed down was the whole problem. This release is
    about making that impossible — and about a node that stops eating the machine it
    lives on.

    Nothing about your addresses, your chain data or your setup changes. Re-run the
    installer on each node and it picks all of this up.

    Why nodes were going dark and staying dark

    Four separate mechanisms, each found in the v0.2.1 code rather than guessed at:

    • DEGRADED was a dead end. Once a transport used up its restart budget, the
      supervisor kept probing it but never repaired it again. The only way back
      was a recovery that happened on its own. Any node that reached this state was
      off the network until a human walked over to it.
    • "The node is down" meant "do nothing", forever. When the chain daemon
      stopped answering, the supervisor correctly refused to restart Tor and I2P —
      and then stopped there. Nothing in the system ever restarted blurtd, its
      container, or Docker.
    • Repairs were never checked. On Linux Mint, tor.service is a wrapper whose
      start command is literally /bin/true, so restarting it can report success
      while the real daemon stays dead. And after five quick failures systemd latches
      a service into a permanent failed state that refuses every further restart until
      someone runs reset-failed — which nothing ever did, including for the
      supervisor itself. Self-healing could be switched off by a single bad minute.
    • The replay flag was pinned forever. A node set up from the block_log kept
      --replay-blockchain in its container command permanently, so every reboot
      re-ran a multi-hour replay. Which looks exactly like "it went down and never
      came back".

    What's new

    • The supervisor now owns the whole node, not just the two transports: the
      chain daemon, the container, the container runtime, the clock, the disk and the
      power settings. A stopped node is started; a missing container is rebuilt from a
      saved spec; a node whose head block has frozen is treated as wedged and
      repaired; a dead Docker is restarted.
    • DEGRADED is now a slow retry, never a grave. It deep-repairs and tries
      again on a doubling backoff (15m → 30m → 60m) for as long as the machine has
      power. Restart thrash is still capped.
    • Every repair is verified. After a restart the supervisor checks that the
      unit really is active with a live process, that the proxy port answers, and that
      the address still exists — and escalates if not. It resolves the real Tor unit
      at runtime instead of trusting a name guessed at install time, and runs
      reset-failed before every restart.
    • Deeper repairs for the failures restarting can never fix: a torrc that lost
      its hidden-service stanza (put back, verified with tor --verify-config, rolled
      back if it would break Tor), an i2pd tunnel file reverted by a package upgrade
      (now written to tunnels.conf.d, where upgrades cannot touch it), and missing
      hidden-service keys (restored from a local backup, so your .onion and
      .b32.i2p survive a purge or a bad restore).
    • Reboots are boring now. The replay flag is removed automatically as soon as
      a node proves it is serving; a new shutdown unit gives the blockchain the full
      time it needs to save itself before Docker goes away, so there are no more dirty
      shutdowns and no surprise replays; and everything is enabled to come back on its
      own. Move a node to another room whenever you like.
    • Laptops stay awake. Suspend, hibernate and the lid switch are disabled at
      the systemd level, where no desktop power setting can override them. If a
      machine does sleep anyway, waking up triggers an immediate full re-check.
    • A controlled reboot as the genuine last resort — only when every transport
      is down, only after two hours of failed repairs, never during a replay, never
      just after booting, at most once a day, and always after stopping the blockchain
      cleanly. Set ALLOW_REBOOT="0" in /etc/hidden-rpc/supervisor.conf to forbid it.

    A much lighter node

    Full detail, with measurements and the trade-offs, in docs/FOOTPRINT.md.

    • No more permanent replay. This was the single largest CPU cost in the fleet,
      and it is gone.
    • The supervisor went from ~104,000 processes a day to roughly 7,000. Its idle
      loop no longer spawns anything at all: it reads /proc with shell builtins
      instead of shelling out to ip, awk, cksum, date and sed several times
      every five seconds. Measured, 200 runs: 5.23 ms → 0.54 ms per network check.
    • Tor circuits cut by ~80%. Health self-dials relax from every 60s to every
      5 minutes once a transport has been steady for half an hour, and snap back
      instantly on any network change, wake-up or failure.
    • I2P stops relaying strangers' traffic. Stock i2pd accepts transit tunnels;
      on a ten-year-old laptop that is the biggest ongoing CPU and bandwidth cost the
      node carries, for no benefit to its own reachability. Now notransit = true,
      with the distro's always-on IRC tunnel switched off too. Your own .b32.i2p
      server tunnel is unaffected.
    • blurtd's web thread pool 256 → 16 (Blurt's own default is 32) and fewer p2p
      connections with a smaller sync prefetch. Neither needs a replay.
    • Optional --headless stops the desktop on a node nobody looks at, freeing
      RAM and the GPU. Reversible with --desktop.

    New commands

    hidden-rpc-status                  # everything: node, reachability, self-repairs, host
    hidden-rpc-status --watch          # live progress, one calm line
    sudo hidden-rpc-nodectl stop       # stop a node safely before unplugging or moving it
    sudo hidden-rpc-nodectl start      # and back on again
    ./installer/hidden-rpc-setup.sh --doctor    # check and repair everything, right now
    

    hidden-rpc-nodectl stop also turns maintenance mode on, so the supervisor leaves
    the node alone while you work; start turns it back off. A node can never be left
    quietly un-supervised. hidden-rpc-transport-status still works and shows the
    transports-only view.

    Upgrading

    Re-run the installer on each node (safe anytime, never harms a node):

    bash installer/hidden-rpc-setup.sh
    

    On a node that is currently pinned to the replay flag, this removes it with one
    short restart — after which reboots take minutes instead of hours. Your
    /etc/hidden-rpc/supervisor.conf is kept as you have it; only the new settings
    this version adds are appended.

    To fix a node without a full installer run: hidden-rpc-setup.sh --doctor.

    Minimum requirements

    • A standard 64-bit PC (amd64), Linux Mint or Ubuntu, Docker-capable.
    • About 90 GB free for a first-time trustless setup.
    • Wired Ethernet is strongly recommended. In this fleet, Wi-Fi connects
      successfully around 50% of the time versus 100% for Ethernet.

    Testing

    Both suites run anywhere, with no Tor, I2P or Docker needed:

    bash supervisor/tests/fsm-sim.sh          # state machine + policy
    bash supervisor/tests/heal-sim.sh         # the repairs themselves
    bash supervisor/tests/installer-lint.sh   # the installer, actually executed
    

    heal-sim.sh drives the repair code against fake systemctl and docker
    commands that reproduce the real traps: the /bin/true Tor wrapper, systemd's
    start limiter, a pinned replay flag, and unless-stopped. The hardware scenarios
    are in docs/SELF-HEALING.md.

    Downloads
  • v0.3.4 514771001b

    agorise released this 2026-09-11 21:21:21 +00:00 | 11 commits to main since this release

    hidden-rpc v0.3.4

    I broke I2P in v0.3.1, and this fixes it

    The low-power i2pd tuning added in v0.3.1 was appended to the end of
    /etc/i2pd/i2pd.conf. That file is an INI file: every key after a [section]
    header belongs to that section. So notransit = true at the end of the file became
    cpuext.notransit, and i2pd refused to start at all:

    unrecognised option 'cpuext.notransit'
    

    Verified against i2pd 2.49. On any node that took v0.3.1-v0.3.3, I2P has been down
    since that install
    — the .onion kept working, so it looked like a flaky tunnel.

    Fixed three ways:

    • the block is now inserted before the first section header, which is the only
      place global options work. Re-running the installer rewrites a misplaced block in
      the right place;
    • applying it is verified: the installer restarts i2pd and checks it actually
      came up. If it did not, the config is put back exactly as it was and you are told
      I2P is running on defaults instead;
    • the supervisor's deep repair now suspects our own changes first: if i2pd is
      down and our managed block is in its config, the block comes out and i2pd is
      restarted without it.

    An optimisation that stops a daemon starting is not an optimisation, and the code
    that adds one has to be able to take it back.

    A replaying node is no longer mistaken for a serving one

    During a block_log replay blurtd answers RPC with head block 1 and stays there for
    hours. v0.3.3 read that as "serving", which started the head-stall timer against a
    node doing exactly what it was told, and tried to strip the replay flag off a replay
    in progress (harmless — the rebuild refuses mid-replay — but it logged an alarming
    warning every minute for hours). The supervisor now checks whether a replay is
    running before calling a node serving, and hidden-rpc-status shows real replay
    progress instead of head block 1.

    A node that cannot open its own database now fixes itself

    On a real node, blurtd was exiting immediately on every start with:

    Chain state does not match block log. Please reindex blockchain.
    

    This is what a hard kill or a power cut leaves behind: blurtd's stored state and the
    block_log disagree, so it refuses to open, exits 1, the container restart policy
    starts it again, and it exits again — forever. Restarting it, rebuilding the
    container, rebooting the machine: none of them can ever help, because the state
    itself has to be rebuilt.

    Two things came out of it.

    A crash loop was being mistaken for a node hard at work. v0.3.2 decided a node
    was busy if its log kept moving — and a crash loop churns its log constantly while
    the container reports running. The supervisor now checks the container runtime's
    restart counter, which is the only thing that tells those two apart, before it
    looks at log activity.

    blurtd's own diagnosis is now read and acted on. It says exactly what is wrong
    and what the fix is, in plain English, in its log. When the supervisor sees that
    message it rebuilds the state by replaying the block_log once — hours, unattended —
    records that it did, and removes the replay flag again as soon as the node serves.
    It will not start a second replay on top of a running one, will not repeat it
    within 12 hours, and will not start one at all while maintenance mode is on.

    The installer handles it too: it reads the old container's log before removing it,
    so a re-run on an affected node starts the rebuild automatically and says what it is
    doing. There is also an explicit command:

    ./installer/hidden-rpc-setup.sh --reindex
    

    hidden-rpc-status reports it as "Rebuilding the chain state — its stored state did
    not match the block_log, so it is replaying once."

    Since v0.3.1: two judgement bugs found on a real node

    v0.3.1 installs and runs. Watching a node come up on real hardware showed two
    places where the supervisor was judging by a stopwatch instead of by evidence.

    1. A slow load could be mistaken for a hang. The node was considered "still
    loading" for a fixed 30 minutes and "stuck" after that. On a machine with a large
    chain on a slow disk, reading the state into memory can take longer — and the one
    mistake that makes things genuinely worse is restarting a node halfway through
    loading, because then it never finishes. The supervisor now asks the node instead:
    if blurtd's log keeps moving, it is working, and it is left alone however long it
    takes. It only acts when the node is running, silent, and not answering — both
    conditions, past both windows (NODE_STALL, default 30 min, and GRACE_NODE, now
    1 hour). hidden-rpc-status says which it is: "its log is still moving, so it is
    working — leave it alone"
    .

    2. Slow probes looked like waking from suspend. Resume detection timed the
    whole loop. But a tick in which both hidden-service self-dials time out
    legitimately takes PROBE_TIMEOUT_TOR + PROBE_TIMEOUT_I2P = 105 seconds, which
    tripped the "woke up" threshold — so an unreachable node forced a full re-check and
    reset its repair ladders on every single cycle. The check now measures the sleep
    only, which is immune to slow probes and still catches a real suspend. Verified: a
    tick spending 8 seconds in probes with a 2-second threshold now produces zero false
    wake-ups.

    Also in this release: the installer no longer holds your terminal for up to 30
    minutes waiting for a node to finish loading. It waits 5 minutes, then hands the
    prompt back and tells you to use hidden-rpc-status --watch — the self-healer is
    already watching the node by then, so there is nothing to sit and guard.


    If you tried v0.3.0: this is the fix

    v0.3.0 could not install. It stopped at "Starting your node" on every machine,
    with no useful explanation. My mistake, and an avoidable one.

    The installer loaded its shared repair library like this:

    DOCKER_CMD="$SUDO docker" . "$SUP_SRC/heal.sh"
    

    A variable assignment written in front of the . builtin is a temporary
    environment assignment: bash throws it away when the command finishes. While it
    was in effect, though, the library's own : "${DOCKER_CMD:=docker}" saw the name
    as already set and skipped its default — so DOCKER_CMD ended up unset, and
    every container command after that ran as timeout 120 run -d …, which fails
    instantly. The library's error went to /dev/null, so all you saw was "the node
    didn't start on this try".

    Fixed in three ways, so it cannot happen again in this shape or any other:

    • one load_heal_lib function does the loading with plain assignments, and
      verifies afterwards that the helpers exist and the command wrappers are
      non-empty — stopping with a clear message if not, before touching anything;
    • container failures now report what the container runtime actually said,
      instead of a shrug;
    • a third test suite, supervisor/tests/installer-lint.sh, runs the real
      start_node out of the real installer against a fake docker and asserts the
      exact command line it produces. That is the test that was missing: v0.3.0's
      supervisor was tested thoroughly and its installer was never executed at all.

    If v0.3.0 removed the container on your node before failing, nothing was lost —
    it was stopped gracefully first and the chain data lives in the Docker volume.
    Re-running the installer rebuilds the container and the node loads its state in
    the usual few minutes. No replay.

    Everything below is the v0.3.0 release, unchanged.


    A node that went down and stayed down was the whole problem. This release is
    about making that impossible — and about a node that stops eating the machine it
    lives on.

    Nothing about your addresses, your chain data or your setup changes. Re-run the
    installer on each node and it picks all of this up.

    Why nodes were going dark and staying dark

    Four separate mechanisms, each found in the v0.2.1 code rather than guessed at:

    • DEGRADED was a dead end. Once a transport used up its restart budget, the
      supervisor kept probing it but never repaired it again. The only way back
      was a recovery that happened on its own. Any node that reached this state was
      off the network until a human walked over to it.
    • "The node is down" meant "do nothing", forever. When the chain daemon
      stopped answering, the supervisor correctly refused to restart Tor and I2P —
      and then stopped there. Nothing in the system ever restarted blurtd, its
      container, or Docker.
    • Repairs were never checked. On Linux Mint, tor.service is a wrapper whose
      start command is literally /bin/true, so restarting it can report success
      while the real daemon stays dead. And after five quick failures systemd latches
      a service into a permanent failed state that refuses every further restart until
      someone runs reset-failed — which nothing ever did, including for the
      supervisor itself. Self-healing could be switched off by a single bad minute.
    • The replay flag was pinned forever. A node set up from the block_log kept
      --replay-blockchain in its container command permanently, so every reboot
      re-ran a multi-hour replay. Which looks exactly like "it went down and never
      came back".

    What's new

    • The supervisor now owns the whole node, not just the two transports: the
      chain daemon, the container, the container runtime, the clock, the disk and the
      power settings. A stopped node is started; a missing container is rebuilt from a
      saved spec; a node whose head block has frozen is treated as wedged and
      repaired; a dead Docker is restarted.
    • DEGRADED is now a slow retry, never a grave. It deep-repairs and tries
      again on a doubling backoff (15m → 30m → 60m) for as long as the machine has
      power. Restart thrash is still capped.
    • Every repair is verified. After a restart the supervisor checks that the
      unit really is active with a live process, that the proxy port answers, and that
      the address still exists — and escalates if not. It resolves the real Tor unit
      at runtime instead of trusting a name guessed at install time, and runs
      reset-failed before every restart.
    • Deeper repairs for the failures restarting can never fix: a torrc that lost
      its hidden-service stanza (put back, verified with tor --verify-config, rolled
      back if it would break Tor), an i2pd tunnel file reverted by a package upgrade
      (now written to tunnels.conf.d, where upgrades cannot touch it), and missing
      hidden-service keys (restored from a local backup, so your .onion and
      .b32.i2p survive a purge or a bad restore).
    • Reboots are boring now. The replay flag is removed automatically as soon as
      a node proves it is serving; a new shutdown unit gives the blockchain the full
      time it needs to save itself before Docker goes away, so there are no more dirty
      shutdowns and no surprise replays; and everything is enabled to come back on its
      own. Move a node to another room whenever you like.
    • Laptops stay awake. Suspend, hibernate and the lid switch are disabled at
      the systemd level, where no desktop power setting can override them. If a
      machine does sleep anyway, waking up triggers an immediate full re-check.
    • A controlled reboot as the genuine last resort — only when every transport
      is down, only after two hours of failed repairs, never during a replay, never
      just after booting, at most once a day, and always after stopping the blockchain
      cleanly. Set ALLOW_REBOOT="0" in /etc/hidden-rpc/supervisor.conf to forbid it.

    A much lighter node

    Full detail, with measurements and the trade-offs, in docs/FOOTPRINT.md.

    • No more permanent replay. This was the single largest CPU cost in the fleet,
      and it is gone.
    • The supervisor went from ~104,000 processes a day to roughly 7,000. Its idle
      loop no longer spawns anything at all: it reads /proc with shell builtins
      instead of shelling out to ip, awk, cksum, date and sed several times
      every five seconds. Measured, 200 runs: 5.23 ms → 0.54 ms per network check.
    • Tor circuits cut by ~80%. Health self-dials relax from every 60s to every
      5 minutes once a transport has been steady for half an hour, and snap back
      instantly on any network change, wake-up or failure.
    • I2P stops relaying strangers' traffic. Stock i2pd accepts transit tunnels;
      on a ten-year-old laptop that is the biggest ongoing CPU and bandwidth cost the
      node carries, for no benefit to its own reachability. Now notransit = true,
      with the distro's always-on IRC tunnel switched off too. Your own .b32.i2p
      server tunnel is unaffected.
    • blurtd's web thread pool 256 → 16 (Blurt's own default is 32) and fewer p2p
      connections with a smaller sync prefetch. Neither needs a replay.
    • Optional --headless stops the desktop on a node nobody looks at, freeing
      RAM and the GPU. Reversible with --desktop.

    New commands

    hidden-rpc-status                  # everything: node, reachability, self-repairs, host
    hidden-rpc-status --watch          # live progress, one calm line
    sudo hidden-rpc-nodectl stop       # stop a node safely before unplugging or moving it
    sudo hidden-rpc-nodectl start      # and back on again
    ./installer/hidden-rpc-setup.sh --doctor    # check and repair everything, right now
    

    hidden-rpc-nodectl stop also turns maintenance mode on, so the supervisor leaves
    the node alone while you work; start turns it back off. A node can never be left
    quietly un-supervised. hidden-rpc-transport-status still works and shows the
    transports-only view.

    Upgrading

    Re-run the installer on each node (safe anytime, never harms a node):

    bash installer/hidden-rpc-setup.sh
    

    On a node that is currently pinned to the replay flag, this removes it with one
    short restart — after which reboots take minutes instead of hours. Your
    /etc/hidden-rpc/supervisor.conf is kept as you have it; only the new settings
    this version adds are appended.

    To fix a node without a full installer run: hidden-rpc-setup.sh --doctor.

    Minimum requirements

    • A standard 64-bit PC (amd64), Linux Mint or Ubuntu, Docker-capable.
    • About 90 GB free for a first-time trustless setup.
    • Wired Ethernet is strongly recommended. In this fleet, Wi-Fi connects
      successfully around 50% of the time versus 100% for Ethernet.

    Testing

    Both suites run anywhere, with no Tor, I2P or Docker needed:

    bash supervisor/tests/fsm-sim.sh          # state machine + policy
    bash supervisor/tests/heal-sim.sh         # the repairs themselves
    bash supervisor/tests/installer-lint.sh   # the installer, actually executed
    

    heal-sim.sh drives the repair code against fake systemctl and docker
    commands that reproduce the real traps: the /bin/true Tor wrapper, systemd's
    start limiter, a pinned replay flag, and unless-stopped. The hardware scenarios
    are in docs/SELF-HEALING.md.

    Downloads
  • v0.3.1 21152a0816

    agorise released this 2026-09-11 20:01:12 +00:00 | 12 commits to main since this release

    hidden-rpc v0.3.1

    If you tried v0.3.0: this is the fix

    v0.3.0 could not install. It stopped at "Starting your node" on every machine,
    with no useful explanation. My mistake, and an avoidable one.

    The installer loaded its shared repair library like this:

    DOCKER_CMD="$SUDO docker" . "$SUP_SRC/heal.sh"
    

    A variable assignment written in front of the . builtin is a temporary
    environment assignment: bash throws it away when the command finishes. While it
    was in effect, though, the library's own : "${DOCKER_CMD:=docker}" saw the name
    as already set and skipped its default — so DOCKER_CMD ended up unset, and
    every container command after that ran as timeout 120 run -d …, which fails
    instantly. The library's error went to /dev/null, so all you saw was "the node
    didn't start on this try".

    Fixed in three ways, so it cannot happen again in this shape or any other:

    • one load_heal_lib function does the loading with plain assignments, and
      verifies afterwards that the helpers exist and the command wrappers are
      non-empty — stopping with a clear message if not, before touching anything;
    • container failures now report what the container runtime actually said,
      instead of a shrug;
    • a third test suite, supervisor/tests/installer-lint.sh, runs the real
      start_node out of the real installer against a fake docker and asserts the
      exact command line it produces. That is the test that was missing: v0.3.0's
      supervisor was tested thoroughly and its installer was never executed at all.

    If v0.3.0 removed the container on your node before failing, nothing was lost —
    it was stopped gracefully first and the chain data lives in the Docker volume.
    Re-running the installer rebuilds the container and the node loads its state in
    the usual few minutes. No replay.

    Everything below is the v0.3.0 release, unchanged — which nobody has been able to
    run until now.


    A node that went down and stayed down was the whole problem. This release is
    about making that impossible — and about a node that stops eating the machine it
    lives on.

    Nothing about your addresses, your chain data or your setup changes. Re-run the
    installer on each node and it picks all of this up.

    Why nodes were going dark and staying dark

    Four separate mechanisms, each found in the v0.2.1 code rather than guessed at:

    • DEGRADED was a dead end. Once a transport used up its restart budget, the
      supervisor kept probing it but never repaired it again. The only way back
      was a recovery that happened on its own. Any node that reached this state was
      off the network until a human walked over to it.
    • "The node is down" meant "do nothing", forever. When the chain daemon
      stopped answering, the supervisor correctly refused to restart Tor and I2P —
      and then stopped there. Nothing in the system ever restarted blurtd, its
      container, or Docker.
    • Repairs were never checked. On Linux Mint, tor.service is a wrapper whose
      start command is literally /bin/true, so restarting it can report success
      while the real daemon stays dead. And after five quick failures systemd latches
      a service into a permanent failed state that refuses every further restart until
      someone runs reset-failed — which nothing ever did, including for the
      supervisor itself. Self-healing could be switched off by a single bad minute.
    • The replay flag was pinned forever. A node set up from the block_log kept
      --replay-blockchain in its container command permanently, so every reboot
      re-ran a multi-hour replay. Which looks exactly like "it went down and never
      came back".

    What's new

    • The supervisor now owns the whole node, not just the two transports: the
      chain daemon, the container, the container runtime, the clock, the disk and the
      power settings. A stopped node is started; a missing container is rebuilt from a
      saved spec; a node whose head block has frozen is treated as wedged and
      repaired; a dead Docker is restarted.
    • DEGRADED is now a slow retry, never a grave. It deep-repairs and tries
      again on a doubling backoff (15m → 30m → 60m) for as long as the machine has
      power. Restart thrash is still capped.
    • Every repair is verified. After a restart the supervisor checks that the
      unit really is active with a live process, that the proxy port answers, and that
      the address still exists — and escalates if not. It resolves the real Tor unit
      at runtime instead of trusting a name guessed at install time, and runs
      reset-failed before every restart.
    • Deeper repairs for the failures restarting can never fix: a torrc that lost
      its hidden-service stanza (put back, verified with tor --verify-config, rolled
      back if it would break Tor), an i2pd tunnel file reverted by a package upgrade
      (now written to tunnels.conf.d, where upgrades cannot touch it), and missing
      hidden-service keys (restored from a local backup, so your .onion and
      .b32.i2p survive a purge or a bad restore).
    • Reboots are boring now. The replay flag is removed automatically as soon as
      a node proves it is serving; a new shutdown unit gives the blockchain the full
      time it needs to save itself before Docker goes away, so there are no more dirty
      shutdowns and no surprise replays; and everything is enabled to come back on its
      own. Move a node to another room whenever you like.
    • Laptops stay awake. Suspend, hibernate and the lid switch are disabled at
      the systemd level, where no desktop power setting can override them. If a
      machine does sleep anyway, waking up triggers an immediate full re-check.
    • A controlled reboot as the genuine last resort — only when every transport
      is down, only after two hours of failed repairs, never during a replay, never
      just after booting, at most once a day, and always after stopping the blockchain
      cleanly. Set ALLOW_REBOOT="0" in /etc/hidden-rpc/supervisor.conf to forbid it.

    A much lighter node

    Full detail, with measurements and the trade-offs, in docs/FOOTPRINT.md.

    • No more permanent replay. This was the single largest CPU cost in the fleet,
      and it is gone.
    • The supervisor went from ~104,000 processes a day to roughly 7,000. Its idle
      loop no longer spawns anything at all: it reads /proc with shell builtins
      instead of shelling out to ip, awk, cksum, date and sed several times
      every five seconds. Measured, 200 runs: 5.23 ms → 0.54 ms per network check.
    • Tor circuits cut by ~80%. Health self-dials relax from every 60s to every
      5 minutes once a transport has been steady for half an hour, and snap back
      instantly on any network change, wake-up or failure.
    • I2P stops relaying strangers' traffic. Stock i2pd accepts transit tunnels;
      on a ten-year-old laptop that is the biggest ongoing CPU and bandwidth cost the
      node carries, for no benefit to its own reachability. Now notransit = true,
      with the distro's always-on IRC tunnel switched off too. Your own .b32.i2p
      server tunnel is unaffected.
    • blurtd's web thread pool 256 → 16 (Blurt's own default is 32) and fewer p2p
      connections with a smaller sync prefetch. Neither needs a replay.
    • Optional --headless stops the desktop on a node nobody looks at, freeing
      RAM and the GPU. Reversible with --desktop.

    New commands

    hidden-rpc-status                  # everything: node, reachability, self-repairs, host
    hidden-rpc-status --watch          # live progress, one calm line
    sudo hidden-rpc-nodectl stop       # stop a node safely before unplugging or moving it
    sudo hidden-rpc-nodectl start      # and back on again
    ./installer/hidden-rpc-setup.sh --doctor    # check and repair everything, right now
    

    hidden-rpc-nodectl stop also turns maintenance mode on, so the supervisor leaves
    the node alone while you work; start turns it back off. A node can never be left
    quietly un-supervised. hidden-rpc-transport-status still works and shows the
    transports-only view.

    Upgrading

    Re-run the installer on each node (safe anytime, never harms a node):

    bash installer/hidden-rpc-setup.sh
    

    On a node that is currently pinned to the replay flag, this removes it with one
    short restart — after which reboots take minutes instead of hours. Your
    /etc/hidden-rpc/supervisor.conf is kept as you have it; only the new settings
    this version adds are appended.

    To fix a node without a full installer run: hidden-rpc-setup.sh --doctor.

    Minimum requirements

    • A standard 64-bit PC (amd64), Linux Mint or Ubuntu, Docker-capable.
    • About 90 GB free for a first-time trustless setup.
    • Wired Ethernet is strongly recommended. In this fleet, Wi-Fi connects
      successfully around 50% of the time versus 100% for Ethernet.

    Testing

    Both suites run anywhere, with no Tor, I2P or Docker needed:

    bash supervisor/tests/fsm-sim.sh          # state machine + policy
    bash supervisor/tests/heal-sim.sh         # the repairs themselves
    bash supervisor/tests/installer-lint.sh   # the installer, actually executed
    

    heal-sim.sh drives the repair code against fake systemctl and docker
    commands that reproduce the real traps: the /bin/true Tor wrapper, systemd's
    start limiter, a pinned replay flag, and unless-stopped. The hardware scenarios
    are in docs/SELF-HEALING.md.

    Downloads
  • v0.3.0 e0ab965755

    agorise released this 2026-09-11 19:46:39 +00:00 | 13 commits to main since this release

    hidden-rpc v0.3.0

    A node that went down and stayed down was the whole problem. This release is
    about making that impossible — and about a node that stops eating the machine it
    lives on.

    Nothing about your addresses, your chain data or your setup changes. Re-run the
    installer on each node and it picks all of this up.

    Why nodes were going dark and staying dark

    Four separate mechanisms, each found in the v0.2.1 code rather than guessed at:

    • DEGRADED was a dead end. Once a transport used up its restart budget, the
      supervisor kept probing it but never repaired it again. The only way back
      was a recovery that happened on its own. Any node that reached this state was
      off the network until a human walked over to it.
    • "The node is down" meant "do nothing", forever. When the chain daemon
      stopped answering, the supervisor correctly refused to restart Tor and I2P —
      and then stopped there. Nothing in the system ever restarted blurtd, its
      container, or Docker.
    • Repairs were never checked. On Linux Mint, tor.service is a wrapper whose
      start command is literally /bin/true, so restarting it can report success
      while the real daemon stays dead. And after five quick failures systemd latches
      a service into a permanent failed state that refuses every further restart until
      someone runs reset-failed — which nothing ever did, including for the
      supervisor itself. Self-healing could be switched off by a single bad minute.
    • The replay flag was pinned forever. A node set up from the block_log kept
      --replay-blockchain in its container command permanently, so every reboot
      re-ran a multi-hour replay. Which looks exactly like "it went down and never
      came back".

    What's new

    • The supervisor now owns the whole node, not just the two transports: the
      chain daemon, the container, the container runtime, the clock, the disk and the
      power settings. A stopped node is started; a missing container is rebuilt from a
      saved spec; a node whose head block has frozen is treated as wedged and
      repaired; a dead Docker is restarted.
    • DEGRADED is now a slow retry, never a grave. It deep-repairs and tries
      again on a doubling backoff (15m → 30m → 60m) for as long as the machine has
      power. Restart thrash is still capped.
    • Every repair is verified. After a restart the supervisor checks that the
      unit really is active with a live process, that the proxy port answers, and that
      the address still exists — and escalates if not. It resolves the real Tor unit
      at runtime instead of trusting a name guessed at install time, and runs
      reset-failed before every restart.
    • Deeper repairs for the failures restarting can never fix: a torrc that lost
      its hidden-service stanza (put back, verified with tor --verify-config, rolled
      back if it would break Tor), an i2pd tunnel file reverted by a package upgrade
      (now written to tunnels.conf.d, where upgrades cannot touch it), and missing
      hidden-service keys (restored from a local backup, so your .onion and
      .b32.i2p survive a purge or a bad restore).
    • Reboots are boring now. The replay flag is removed automatically as soon as
      a node proves it is serving; a new shutdown unit gives the blockchain the full
      time it needs to save itself before Docker goes away, so there are no more dirty
      shutdowns and no surprise replays; and everything is enabled to come back on its
      own. Move a node to another room whenever you like.
    • Laptops stay awake. Suspend, hibernate and the lid switch are disabled at
      the systemd level, where no desktop power setting can override them. If a
      machine does sleep anyway, waking up triggers an immediate full re-check.
    • A controlled reboot as the genuine last resort — only when every transport
      is down, only after two hours of failed repairs, never during a replay, never
      just after booting, at most once a day, and always after stopping the blockchain
      cleanly. Set ALLOW_REBOOT="0" in /etc/hidden-rpc/supervisor.conf to forbid it.

    A much lighter node

    Full detail, with measurements and the trade-offs, in docs/FOOTPRINT.md.

    • No more permanent replay. This was the single largest CPU cost in the fleet,
      and it is gone.
    • The supervisor went from ~104,000 processes a day to roughly 7,000. Its idle
      loop no longer spawns anything at all: it reads /proc with shell builtins
      instead of shelling out to ip, awk, cksum, date and sed several times
      every five seconds. Measured, 200 runs: 5.23 ms → 0.54 ms per network check.
    • Tor circuits cut by ~80%. Health self-dials relax from every 60s to every
      5 minutes once a transport has been steady for half an hour, and snap back
      instantly on any network change, wake-up or failure.
    • I2P stops relaying strangers' traffic. Stock i2pd accepts transit tunnels;
      on a ten-year-old laptop that is the biggest ongoing CPU and bandwidth cost the
      node carries, for no benefit to its own reachability. Now notransit = true,
      with the distro's always-on IRC tunnel switched off too. Your own .b32.i2p
      server tunnel is unaffected.
    • blurtd's web thread pool 256 → 16 (Blurt's own default is 32) and fewer p2p
      connections with a smaller sync prefetch. Neither needs a replay.
    • Optional --headless stops the desktop on a node nobody looks at, freeing
      RAM and the GPU. Reversible with --desktop.

    New commands

    hidden-rpc-status                  # everything: node, reachability, self-repairs, host
    hidden-rpc-status --watch          # live progress, one calm line
    sudo hidden-rpc-nodectl stop       # stop a node safely before unplugging or moving it
    sudo hidden-rpc-nodectl start      # and back on again
    ./installer/hidden-rpc-setup.sh --doctor    # check and repair everything, right now
    

    hidden-rpc-nodectl stop also turns maintenance mode on, so the supervisor leaves
    the node alone while you work; start turns it back off. A node can never be left
    quietly un-supervised. hidden-rpc-transport-status still works and shows the
    transports-only view.

    Upgrading

    Re-run the installer on each node (safe anytime, never harms a node):

    bash installer/hidden-rpc-setup.sh
    

    On a node that is currently pinned to the replay flag, this removes it with one
    short restart — after which reboots take minutes instead of hours. Your
    /etc/hidden-rpc/supervisor.conf is kept as you have it; only the new settings
    this version adds are appended.

    To fix a node without a full installer run: hidden-rpc-setup.sh --doctor.

    Minimum requirements

    • A standard 64-bit PC (amd64), Linux Mint or Ubuntu, Docker-capable.
    • About 90 GB free for a first-time trustless setup.
    • Wired Ethernet is strongly recommended. In this fleet, Wi-Fi connects
      successfully around 50% of the time versus 100% for Ethernet.

    Testing

    Both suites run anywhere, with no Tor, I2P or Docker needed:

    bash supervisor/tests/fsm-sim.sh    # state machine + policy  -> ALL FSM TESTS PASSED
    bash supervisor/tests/heal-sim.sh   # the repairs themselves  -> ALL HEAL TESTS PASSED
    

    heal-sim.sh drives the repair code against fake systemctl and docker
    commands that reproduce the real traps: the /bin/true Tor wrapper, systemd's
    start limiter, a pinned replay flag, and unless-stopped. The hardware scenarios
    are in docs/SELF-HEALING.md.

    Downloads
  • v0.2.1 8ac1c6a714

    agorise released this 2026-08-30 02:28:09 +00:00 | 14 commits to main since this release

    hidden-rpc v0.2.1

    A small follow-up to v0.2.0 that makes first-time sync readable. No behaviour
    change to the node or the self-healer — just clearer status while a fresh node is
    still catching up.

    What's fixed

    • "Syncing" instead of a scary "rpc-down" during first sync. While a brand-new
      node is still replaying the block_log, its RPC isn't up yet, so transport status
      showed ⚠ rpc-down. It now reads – Syncing; be patient. The blunt ⚠ rpc-down
      warning is kept for the case that actually matters: a node that was serving and
      whose RPC later stops (tracked by a persisted "has the RPC ever answered" flag),
      so a real outage is never hidden behind a reassuring message.
    • --watch shows real replay progress. During the block_log replay the
      progress line was scraping the largest number in blurtd's logs — which is always
      the block_log's total size — so it looked frozen (e.g. stuck at 62905338 for
      hours). It now parses blurtd's actual replay line and shows the current block,
      the total, and the percent, e.g. block 31400000 of 62905338 (49.9163%).

    Upgrading

    Re-run the installer on each node to pick it up (safe anytime, never harms a node):

    bash installer/hidden-rpc-setup.sh
    

    The new – Syncing; be patient label appears once the updated supervisor is
    running; on already-synced nodes you'll simply keep seeing healthy.

    Downloads
  • v0.2.0 c337cdba38

    agorise released this 2026-08-29 01:18:50 +00:00 | 15 commits to main since this release

    hidden-rpc v0.2.0

    Your node now heals its own Tor and I2P reachability. If a transport goes
    dark — whether the daemon crashed or is merely stuck (still active (running)
    but not serving) — the node detects it and repairs it on its own, per transport,
    with no reboot and no SSH. This closes the gap behind the oldpc incident: after a
    Wi-Fi→Ethernet swap, i2pd rebuilt its tunnels in seconds but tor stayed "running"
    while its onion silently went dark for an hour. Process liveness was never the
    right signal; end-to-end reachability is.

    Already-synced nodes are unaffected — this only adds a background self-healer.

    What's new in v0.2.0

    • End-to-end self-probing, per transport. The node dials its own .onion
      and .b32.i2p back through the real circuit/tunnel and makes a live RPC call —
      the only check that catches a "stuck but running" daemon.
    • Transport-down vs RPC-down. A loopback RPC check gates every repair, so a
      down RPC never triggers a pointless tor/i2pd restart.
    • Graduated, least-disruptive repair. Gentle nudge → restart → escalate, each
      with a grace window sized to real onion-descriptor / I2P-tunnel rebuild time.
    • Network-change awareness. An interface/route/IP change (the oldpc trigger)
      forces an immediate re-probe of both transports instead of waiting a cycle.
    • Independent Tor and I2P supervision. A healthy transport never masks a
      broken one — the exact way the oldpc outage stayed invisible.
    • Flap protection. An hourly restart cap and a per-episode cycle limit; an
      unrecoverable transport backs off to degraded instead of restart-looping.
    • Self-reported status. hidden-rpc-transport-status (and --status,
      --transports) show each transport as healthy / recovering / degraded
      and when it last auto-recovered. Morphit's directory can read this to show
      recovery state authoritatively rather than guessing.
    • Runs itself, safely. Installed as a systemd service that is itself
      restarted if it ever dies, and it only ever restarts tor/i2pd — nothing else.

    The self-healer installs automatically on your next hidden-rpc-setup.sh run,
    once the node has a Tor or I2P address. Tunables (probe cadence, grace windows,
    restart caps) live in /etc/hidden-rpc/supervisor.conf.

    Carried over: optional --name <handle>; --watch replay animation; trustless
    on-chain bootstrap; --mirror-only; runnable command paths.

    Minimum requirements

    • Operating system: 64-bit Linux in the Debian / Ubuntu / Linux Mint family
      (uses apt). Tested on Linux Mint 22 and Ubuntu 24.04.

    • Architecture: amd64 / x86_64. ARM is not supported yet.

    • Memory: ~4 GB RAM minimum (~3 GB used by the node); 8 GB comfortable.

    • Free disk space: about 100 GB for a first-time setup; far less later. An
      SSD is strongly recommended — the one-time replay is far faster on an SSD.

    • Internet: a wired LAN / Ethernet connection is strongly recommended. A
      node on Wi-Fi only sees roughly a 50% successful connection rate; on
      Ethernet you get 100% connectivity, which is what an RPC node actually needs
      to stay reachable and keep re-publishing its hidden endpoints. Wi-Fi will run,
      but expect the transport self-healer to spend more time recovering and your
      uptime to suffer. A serving node keeps a clearnet p2p connection on port 1776 to
      stay in sync; only the RPC reads are hidden over Tor and I2P.

    • Installed automatically if missing: Docker, Tor, i2pd, and small tools.

    • Repository: https://git.agorise.net/agorise/hidden-rpc

    • License: AGPL-3.0-or-later

    Downloads
  • v0.1.17 b0ed2734bf

    agorise released this 2026-08-26 17:54:28 +00:00 | 16 commits to main since this release

    hidden-rpc v0.1.17

    Adds an optional, opt-in name for a node — so an operator who wants to be
    identifiable (e.g. to be pinged when their node needs a reboot) can be, while
    anonymity-preferring operators simply leave it blank and leak nothing. No change
    to how the node runs; already-synced nodes are unaffected.

    What's new in v0.1.17

    • --name <handle> — an optional public handle for this node. Set one with
      --name oldpc (or a Blurt @handle); clear it with --name "". It's blank by
      default. When set, the name:
      • shows in --status and --show-addresses, so you can tell which machine you're on;
      • is saved into node-addresses.json alongside the .onion / .b32.i2p, so the
        node's directory entry is copy-paste ready.
        The handle is validated to a safe, chain-friendly charset (1–32 of letters,
        digits, and . _ - @) — the SAME rules Morphit's on-chain RPC-directory accepts,
        so a name set here can be pinned as-is. It's a cosmetic label only and never
        changes how the node is reached.

    Carried over: --watch animates during replay and returns to the prompt once
    fully synced; runnable command paths; empty snapshot-folder cleanup; minimum
    requirements in the notes; trustless on-chain bootstrap; --mirror-only.

    Minimum requirements

    • Operating system: 64-bit Linux in the Debian / Ubuntu / Linux Mint family
      (uses apt). Tested on Linux Mint 22 and Ubuntu 24.04.

    • Architecture: amd64 / x86_64. ARM is not supported yet.

    • Memory: ~4 GB RAM minimum (~3 GB used by the node); 8 GB comfortable.

    • Free disk space: about 100 GB for a first-time setup; far less later. An
      SSD is strongly recommended — the one-time replay is far faster on an SSD.

    • Internet: normal broadband. A serving node keeps a clearnet p2p connection
      on port 1776 to stay in sync; only the RPC reads are hidden over Tor and I2P.

    • Installed automatically if missing: Docker, Tor, i2pd, and small tools.

    • Repository: https://git.agorise.net/agorise/hidden-rpc

    • License: AGPL-3.0-or-later

    Downloads
  • v0.1.16 abbd4355ec

    agorise released this 2026-08-24 19:59:00 +00:00 | 17 commits to main since this release

    hidden-rpc v0.1.16

    Setup- and monitoring-experience polish. No change to the node itself; already-synced nodes are
    unaffected.

    What's new

    • --watch behaves properly end to end. While the node replays the block_log (before the RPC
      answers), --watch now shows a live braille spinner, a "take a break — your CPU will be busy for
      a few hours" message, and a live (block N of ~N) readout pulled from the node's own logs. Once
      the RPC is up it shows the catch-up percentage. And the moment the node is fully synced, --watch
      prints a confirmation and returns you to the prompt automatically
      — no more sitting on a static
      screen waiting to press Ctrl-C.
    • Suggested commands are copy-paste runnable. End-of-setup hints (and the "check progress" /
      "not running yet" messages) print the full absolute path the installer was launched from —
      e.g. bash /home/you/hidden-rpc/installer/hidden-rpc-setup.sh --status — with a trailing
      # comment so pasting the whole line still runs.
    • The empty snapshot download folder is removed after the download is unpacked and deleted
      (via rmdir, which only deletes an already-empty directory).

    Minimum requirements

    • Operating system: 64-bit Linux in the Debian / Ubuntu / Linux Mint family (anything that uses
      apt). Tested on Linux Mint 22 and Ubuntu 24.04; other recent Debian-based distros should work.

    • Architecture: amd64 / x86_64 (a standard 64-bit PC). ARM is not supported yet.

    • Memory: ~4 GB RAM minimum (the node itself uses about 3 GB); 8 GB is comfortable.

    • Free disk space: about 100 GB for a first-time setup (the download plus the state the node
      rebuilds while replaying); far less on later runs. An SSD is strongly recommended — the
      one-time replay is dramatically faster on an SSD than on a spinning hard drive.

    • Internet: a normal broadband connection. A serving node keeps a clearnet peer-to-peer
      connection on port 1776 to stay in sync; only the RPC reads are hidden over Tor and I2P.

    • Time: the one-time trustless replay re-verifies every block and keeps the CPU busy for several
      hours on first setup. After that the node keeps up on its own with negligible load.

    • Installed automatically if missing: Docker, Tor, i2pd, and a few small command-line tools — no
      manual setup required.

    • Repository: https://git.agorise.net/agorise/hidden-rpc

    • License: AGPL-3.0-or-later

    Downloads
  • v0.1.14 4bbdf14208

    agorise released this 2026-08-24 06:22:07 +00:00 | 18 commits to main since this release

    hidden-rpc v0.1.14

    A documentation-accuracy and audit release. No behavior change from v0.1.13 — this makes the docs
    match how the installer actually works now (trustless by default), records the genesis finding, and
    ships a clean full-audit pass. Already-synced nodes are unaffected.

    What's in this release

    • Docs now describe the real default flow. installer/README.md, docs/MANUAL-SETUP.md, and the
      top-level README.md were updated: the default is the trustless bootstrap (signed on-chain
      chain_snapshot_v1 pointer → SHA-256-verified block_log from IPFS/mirror → genesis file →
      replay), with --trusted-state as the fast presynced-state opt-in. --check-snapshot and
      --mirror-only are documented, and the genesis-file requirement is written down.
    • Decisions log updated with the genesis-required-for-replay finding and the publisher action
      item (bundle snapshot.json in the pinned archive, or host it with genesis_cid+genesis_sha256
      in the op).
    • Full audit pass: every script shellcheck-clean (info level) and bash -n clean; the pointer
      validator compiles and passes its unit tests; no orphaned/unwired functions; embedded fallback
      config matches the shipped config.ini (loopback, no witness, follow_api, identical seeds).

    Carried over: dead IPFS gateway removed and graceful failure when the genesis can't be fetched
    (v0.1.13); genesis placement (v0.1.12); spinner-on-every-step UX (v0.1.11); --mirror-only and real
    IPFS_GATEWAYS="" (v0.1.10); live progress + fast fail-over (v0.1.9); trustless bootstrap
    (v0.1.6–v0.1.8).

    Reliable path today

    Public IPFS gateways don't yet reliably serve Blurt's genesis file, so a from-scratch trustless
    replay can't always complete until the snapshot publisher bundles the genesis. For a guaranteed
    setup right now, use the mirror-backed fast path:

    bash installer/hidden-rpc-setup.sh --trusted-state
    

    Important

    Tor and I2P hide where you read, not whether what you read is true — cross-check across
    independent nodes. RPC-only (no witness / block production).

    Downloads
  • v0.1.8 7065efe7c2

    agorise released this 2026-08-21 04:40:22 +00:00 | 19 commits to main since this release

    Signed by agorise
    GPG key ID: 53524E1F1017EB9C

    hidden-rpc v0.1.8

    Makes the trustless download robust no matter how a snapshot is pinned or how busy the IPFS network
    is. Small, download-path-only changes; nodes already synced are unaffected.

    What's new in v0.1.8

    • Works whether the snapshot CID is a bare file or a wrapped directory. The current snapshot is
      a raw file CID (so it already worked), but future or community-pinned snapshots might be wrapped.
      The installer now also tries <gateway>/ipfs/<cid>/block_log-<block_height>.tar.zst, so either
      layout resolves. All sources serve identical bytes; the SHA-256 gate remains the final check.
    • Prompt failover to the mirror. IPFS gateways now have connect and inactivity timeouts, so a
      slow or not-yet-propagated gateway hands off to the Forgejo mirror quickly instead of stalling —
      and once your node has the file, it helps reseed IPFS for the next person.

    Carried over: trustless block_log bootstrap from the signed on-chain chain_snapshot_v1 pointer
    (cross-checked across RPCs, SHA-256 gated, replayed and re-verified), zstd/.tar.zst support,
    the --trusted-state opt-in, --check-snapshot, and the clearnet p2p disclosure at setup.

    Verify the live pointer (no download)

    bash installer/hidden-rpc-setup.sh --check-snapshot
    

    Important

    Tor and I2P hide where you read, not whether what you read is true — cross-check across
    independent nodes. RPC-only (no witness / block production).

    Downloads