# 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 / 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.