Sami Ahmed bff90dc9b2 Initial CAC3 explorer — design doc, license, config schema.
This is a docs-only seed. Tomorrow's session will add the actual Go
source: main.go, internal/rpc/client.go (JSON-RPC + cookie auth),
internal/chain/, internal/explorer/ (handlers), and internal/view/
(templates + static assets, embed.FS).

Until then this commit gives the repo its shape: README with the full
design, config example with all knobs, MIT license to match the
chain, and a .gitignore for Go build artifacts.
2026-07-16 03:01:46 -07:00

CAC3 Explorer

A Go single-binary block explorer for CAC3 (Californiacoin3). Reads from a running cac3d node over its JSON-RPC interface (Bitcoin Core 0.18 style — cookie auth).

What it shows

  • Home / chain tip — current height, best block hash, difficulty, network hashrate, mempool size, last 10 blocks
  • Block detail — by height or hash; full header, transactions, next/prev navigation
  • Transaction detail — by txid; inputs/outputs with script-decoded addresses, value, confirmations
  • Address detail — balance, total received/sent, UTXO list, recent tx history
  • Mempool — current tx pool with fee/sat-per-byte sort

Why Go

  • One statically-linked binary — no runtime, no node_modules, no Python deps
  • Cold start ~30ms, idle RSS ~15MB
  • Embeds templates + static assets via embed.FS — single artifact deploy
  • Native HTTP/2, easy systemd integration, fits the same deployment shape as DashCaddy / Triangles

Quick start

1. Build

go build -ldflags="-s -w" -o cac3-explorer .
# or with a version stamp
go build -ldflags="-s -w -X main.Version=$(git describe --tags --always)" -o cac3-explorer .

Static binary, no glibc dep, runs anywhere.

2. Configure

The explorer reads config from (in priority order):

  1. Flags (--rpc-url, --cookie-path, --listen, etc.)
  2. Env vars (CAC3_RPC_URL, CAC3_COOKIE_PATH, CAC3_LISTEN, …)
  3. config.yaml in the working directory

Example config.yaml:

listen: "0.0.0.0:8080"
rpc:
  url: "http://127.0.0.1:8332"
  cookie_path: "/var/lib/cac3/.cookie"
  # OR static creds (less secure, but useful for testing):
  # user: "cac3rpc"
  # pass: "changeme"
  timeout: "10s"

chain:
  name: "CAC3 Mainnet"
  ticker: "CAC3"
  # site URL used in <link rel="canonical"> / OG tags
  site_url: "https://explorer.cac3.example"

# Address-link overrides — point these at your public node, block explorers, etc.
links:
  # tx / address / block pages can deep-link to external tools if set
  # wallet: "https://wallet.cac3.example"

3. Run

./cac3-explorer --config config.yaml
# or fully env-var driven
CAC3_RPC_URL=http://127.0.0.1:8332 \
CAC3_COOKIE_PATH=/var/lib/cac3/.cookie \
CAC3_LISTEN=0.0.0.0:8080 \
./cac3-explorer

Open http://localhost:8080.

4. systemd (optional)

# /etc/systemd/system/cac3-explorer.service
[Unit]
Description=CAC3 Block Explorer
After=network.target cac3d.service
Wants=cac3d.service

[Service]
Type=simple
User=cac3-explorer
Group=cac3-explorer
WorkingDirectory=/opt/cac3-explorer
ExecStart=/opt/cac3-explorer/cac3-explorer --config /etc/cac3-explorer/config.yaml
Restart=on-failure
RestartSec=5s
NoNewPrivileges=true
ProtectSystem=strict
ReadWritePaths=/var/log/cac3-explorer

[Install]
WantedBy=multi-user.target

RPC surface used

The explorer only needs a non-wallet cac3d node (no wallet.dat required, no signing keys). Methods called:

Method Used for
getblockchaininfo tip, difficulty, chainwork
getnetworkinfo protocol version, connections
getmininginfo hashrate, blocks
getmempoolinfo mempool size, bytes
getrawmempool mempool txid list
getblockhash height → hash
getblock block header + tx list (verbose=1)
getblockheader header only
getrawtransaction tx hex by txid
decoderawtransaction decode inputs/outputs
gettxoutsetinfo total supply stats
getconnectioncount peer count
getdifficulty current difficulty (decimal)
listsinceblock recent wallet-scoped activity (only if --show-wallet enabled)

No sendtoaddress, no signing, no key access. Safe to expose the RPC port on a private interface (or behind SSH tunnel) — the explorer's only attack surface is the read path.

Repo layout

.
├── main.go                  # entrypoint, config, signal handling
├── internal/
│   ├── rpc/                 # cac3d JSON-RPC client + cookie auth
│   │   ├── client.go
│   │   ├── auth.go          # cookie + userpass
│   │   └── types.go         # raw RPC types
│   ├── chain/               # domain types (Block, Tx, Address, …)
│   │   └── types.go
│   ├── explorer/            # handlers
│   │   ├── home.go
│   │   ├── block.go
│   │   ├── tx.go
│   │   ├── address.go
│   │   └── mempool.go
│   └── view/                # templates + render
│       ├── templates/       # html/template files (embed.FS)
│       └── static/          # css, js, favicon (embed.FS)
├── config.example.yaml
├── go.mod
├── go.sum
├── LICENSE                  # MIT, matches the chain license
└── README.md

Security notes

  • Cookie auth is preferredcac3d rotates .cookie on every restart. Re-read on every request (cheap, file is ~1KB).
  • The explorer is read-only. It never sends sendtoaddress / signrawtransaction / walletlock. To prove this, search the source for those method names — they should not appear.
  • Do not expose cac3d's RPC port to the public internet. Bind it to 127.0.0.1 or a tailnet IP and let the explorer be the only public entry point.
  • The explorer binds to whatever --listen says. Use a reverse proxy (Caddy / nginx) for TLS, rate limiting, and a real domain.

Development

# run with hot-reload (needs `air` or similar; not required)
go run .

# test
go test ./...

# vet / lint
go vet ./...
staticcheck ./...   # if installed

The first request after cac3d start will be slow (RPC cold cache). Subsequent requests are <50ms for blocks, <200ms for address histories.

License

MIT — see LICENSE. This explorer is a separate project from the CAC3 chain code; it only depends on cac3d's documented JSON-RPC interface.

S
Description
CAC3 (Californiacoin3) block explorer — Go single binary, reads cac3d RPC.
Readme 33 KiB