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:
+31
@@ -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/
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
Reference in New Issue
Block a user