Files
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

180 lines
5.8 KiB
Markdown

# CAC3 Explorer
A Go single-binary block explorer for [CAC3 (Californiacoin3)](https://github.com/SamiAhmed7777/cac3).
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
```bash
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`:
```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
```bash
./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)
```ini
# /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 preferred** — `cac3d` 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
```bash
# 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](LICENSE). This explorer is a separate project from the CAC3 chain code; it only depends on `cac3d`'s documented JSON-RPC interface.