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.
This commit is contained in:
Sami Ahmed
2026-07-16 03:01:46 -07:00
commit bff90dc9b2
4 changed files with 278 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
# Go
/bin/
/dist/
*.exe
*.test
*.out
coverage.txt
*.prof
# Local config / secrets
.env
config.local.yaml
*.cookie
# Editor / OS
.DS_Store
.idea/
.vscode/
*.swp
*~
# Build cache
/tmp/
/cac3-explorer
/cac3-explorer-*
# Go modules (commit if not vendored; comment out if vendoring)
# vendor/
# Tailwind / static build cache
/static/css/.tailwind-cache/
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Sami Ahmed
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+179
View File
@@ -0,0 +1,179 @@
# 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.
+47
View File
@@ -0,0 +1,47 @@
# CAC3 Explorer — example config
# Copy to config.yaml and edit, or override via flags / env vars.
listen: "0.0.0.0:8080"
rpc:
# Bitcoin Core 0.18 / cac3d JSON-RPC endpoint
url: "http://127.0.0.1:8332"
# Path to cac3d's .cookie file (preferred — auto-rotated on daemon restart).
cookie_path: "/var/lib/cac3/.cookie"
# OR static creds (less secure, but useful for tests):
# user: "cac3rpc"
# pass: "changeme"
timeout: "10s"
# How often to refresh the cookie file from disk. cac3d only writes it on
# startup, so this is mostly a safety net.
cookie_refresh: "30s"
chain:
name: "CAC3 Mainnet"
ticker: "CAC3"
site_url: "https://explorer.example.com"
# Decimal places for coin amounts. CAC3 follows Bitcoin's 8.
coin_decimals: 8
# Block time target in seconds (used for ETA / hashrate estimates).
block_time_seconds: 10
# Public-facing links shown in the header. Leave empty strings to hide.
links:
website: "https://cac3.example.com"
github: "https://github.com/SamiAhmed7777/cac3"
# Optional: deep-link tx / address / block pages to another explorer
# (e.g. if you want a sister explorer for a sister chain)
# alt_explorer: "https://alt-explorer.example.com"
# Cache layer (in-memory by default). Set redis_url to share cache across replicas.
cache:
backend: "memory" # "memory" | "redis"
ttl: "30s"
# redis_url: "redis://127.0.0.1:6379/0"
# UI
ui:
# Set false to disable the "Search" box (e.g. if fronted by an external search)
show_search: true
# Page footer copyright
footer: "© 2026 CAC3 Project"