- Shell 87.6%
- Python 12.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| config | ||
| docs | ||
| installer | ||
| .gitignore | ||
| LICENSE | ||
| README.md | ||
| RELEASE-NOTES.md | ||
| release.sh | ||
| VERSION | ||
hidden-rpc
A self-contained package that turns an ordinary machine (an old laptop is enough) into a
censorship-resistant Blurt RPC node, reachable over Tor (.onion v3) and I2P (.b32.i2p) —
with no public IP, no port-forward, no DNS, no registrar, and no hosting company.
It bundles a full blurtd + a hidden-service transport layer + grandma-friendly operator
tooling, so any Blurt RPC admin can stand up a node on hardware they already own.
- Home:
git.agorise.net/agorise/hidden-rpc(Forgejo) - License: AGPL-3.0-or-later
- Status: Phase 0 (scaffold). See
docs/ROADMAP.md.
What this is — and what it is NOT
It is
A packaging/transport/tooling layer that wraps existing upstreams. It does not fork or
re-implement blurtd (or, later, Nexus) — it consumes them as upstream dependencies and adds
the value on top: self-authenticating hidden-service reachability, JSON-RPC batch support, and
one-command operator setup that stays calm on flaky home hardware.
Wrap, don't fork. If we ever find ourselves patching
blurtdinternals, we've taken a wrong turn. Fixes to the chain node go upstream; this repo owns the layer around it.
It is NOT
- Not a witness / block-production tool. p2p block gossip over Tor is latency-sensitive and
chain-wide — out of scope. (A witness may also expose their RPC as
.onionwith this package; that's fine. Block production over Tor is not.) - Not a naming/addressing system. No vanity
.i2paddressbook, no.loki/LNS. RPC endpoints are machine-to-machine — nobody types them — so memorability buys nothing while re-introducing a naming-trust dependency. We support only raw.onionv3 +.b32.i2p, both of which are self-authenticating (the address is the key hash) and therefore strictly stronger than clearnet + TLS + DNS. - Not a trust layer. This package makes a trustworthy-transport node. Whether a given node's answers are true is a separate problem solved by the reader (see below).
The trust caveat (load-bearing — read this)
Tor/I2P hide where you read, not whether what you read is true.
Reaching a node over a hidden service tells you nothing about the honesty of its data. Cross- checking and quorum — racing the same call at several independent nodes and requiring them to agree before trusting a head block or balance — is the reader's responsibility. In the Agorise stack that reader is Morphit, which implements race + quorum as a parallel track in its own repo.
Nothing in this package's docs or output should ever imply that reaching a node means trusting its data. If you catch such an implication, it's a bug.
Local blurtd is still the gold standard. The strongest reader runs its own blurtd and
reads localhost. This package's hidden-RPC tier is the fallback for readers too small to
hold the chain, or for onion-only / locked-down environments.
Relationship to Morphit
hidden-rpc is a separate project from Morphit, with a different audience (all Blurt RPC
admins, not only Morphit operators) and an independent release cadence.
- Morphit consumes these nodes. It reads the chain through them and publishes the on-chain
directory (
morphit_rpc_v1, signed by@morphit) that lists them. - Morphit does not own this software. This repo does not know about the marketplace; it just exposes a chain node over a hidden service and emits its address in a form Morphit's registration tooling can pick up.
- The
morphit_rpc_v1op is defined and broadcast in the Morphit repo, not here.
Why "outbound-only" is the whole point
Hidden services dial out. There is no inbound connection to accept, so there is no public IP to obtain, no port to forward, no registrar to satisfy, and no CGNAT/ISP-NAT problem. A laptop behind a typical home router — or behind carrier-grade NAT — can serve RPC to the world without any cooperation from the ISP.
Flaky by design
Laptops sleep; home internet flaps. Per-node uptime is not the goal — the union of nodes being reachable is. We do not engineer per-node high-availability. We engineer for trivial add/remove of nodes and clean "just doesn't answer" failure. (Morphit's race + failover handles the consumer side.)
Repository layout
hidden-rpc/
├── README.md ← you are here
├── LICENSE ← AGPL-3.0-or-later
├── VERSION ← current release version (used by release.sh)
├── RELEASE-NOTES.md ← notes for the current release
├── release.sh ← maintainer: one-command publish to Forgejo
├── config/
│ ├── config.ini ← ready-to-use: upstream config, webserver bound to loopback
│ └── rpc-config.upstream.ini ← Blurt-published config, verbatim (provenance)
├── installer/
│ ├── hidden-rpc-setup.sh ← one-command auto-installer (Phase 2; first run = Phase 1 proof)
│ └── README.md ← installer usage
└── docs/
├── ROADMAP.md ← build order, phases 0–6
├── DECISIONS.md ← settled + open decisions log
├── GAPS.md ← gap analysis of the upstream setup instructions
└── MANUAL-SETUP.md ← Phase 1: the one-laptop proof, reproducible by hand
Current status & next step
Released and running. The one-command installer (installer/hidden-rpc-setup.sh) is the canonical
setup — by default it trustlessly bootstraps the chain from a signed on-chain pointer
(chain_snapshot_v1 by @morphit): it fetches the block_log (IPFS, mirror fallback), verifies its
SHA-256, places Blurt's genesis file, and replays every block. It binds the RPC to loopback, stands
up the Tor and I2P hidden services, and prints the node's two addresses. It's idempotent,
self-cleaning, and survives reboots. A --trusted-state opt-in sets up fast from a presynced state
snapshot (you trust its publisher). Three nodes are live over both networks.
./installer/hidden-rpc-setup.sh
For how it works under the hood (and the manual equivalent), see
docs/MANUAL-SETUP.md. The reasoning and the resolved unknowns are in
docs/DECISIONS.md; the roadmap and what's left (Nexus, Morphit handoff) are
in docs/ROADMAP.md.