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