feat: Add trashscan-explorer stack for Gorbagana blockchain explorer
Add a complete stack for deploying TrashScan-Explorer, a blockchain explorer for Gorbagana mainnet (Solana fork). ## New Files Stack definition: - stacks/trashscan-explorer/stack.yml - stacks/trashscan-explorer/README.md Container build: - container-build/cerc-trashscan-explorer/Dockerfile.base - container-build/cerc-trashscan-explorer/Dockerfile - container-build/cerc-trashscan-explorer/build.sh - container-build/cerc-trashscan-explorer/scripts/start-explorer.sh Compose: - compose/docker-compose-trashscan-explorer.yml ## Components - trashscan-explorer: React/Express blockchain explorer (port 5001) - trashscan-db: PostgreSQL 14 database ## Usage ```bash laconic-so --stack trashscan-explorer setup-repositories laconic-so --stack trashscan-explorer build-containers laconic-so --stack trashscan-explorer deploy-system up ``` Access at http://localhost:5001 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>feat/trashscan-explorer-stack
parent
ccccd9f957
commit
ed676c00c9
|
|
@ -0,0 +1,47 @@
|
||||||
|
services:
|
||||||
|
trashscan-db:
|
||||||
|
image: postgres:14-alpine
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${TRASHSCAN_DB_USER:-trashscan}
|
||||||
|
POSTGRES_PASSWORD: ${TRASHSCAN_DB_PASSWORD:-password}
|
||||||
|
POSTGRES_DB: ${TRASHSCAN_DB_NAME:-trashscan}
|
||||||
|
POSTGRES_INITDB_ARGS: "-E UTF8 --locale=C"
|
||||||
|
volumes:
|
||||||
|
- trashscan_db_data:/var/lib/postgresql/data
|
||||||
|
ports:
|
||||||
|
- "5432"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "pg_isready", "-U", "trashscan"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
start_period: 5s
|
||||||
|
|
||||||
|
trashscan-explorer:
|
||||||
|
image: cerc/trashscan-explorer:local
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
trashscan-db:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
NODE_ENV: production
|
||||||
|
DATABASE_URL: ${DATABASE_URL:-postgres://trashscan:password@trashscan-db:5432/trashscan}
|
||||||
|
PORT: ${TRASHSCAN_PORT:-5000}
|
||||||
|
SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production}
|
||||||
|
RPC_URL: ${RPC_URL:-https://rpc.trashscan.io/}
|
||||||
|
RUN_MIGRATIONS: ${RUN_MIGRATIONS:-true}
|
||||||
|
CERC_SCRIPT_DEBUG: ${CERC_SCRIPT_DEBUG}
|
||||||
|
ports:
|
||||||
|
- "${TRASHSCAN_HOST_PORT:-5001}:5000"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "nc", "-z", "localhost", "5000"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 10
|
||||||
|
start_period: 30s
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
trashscan_db_data:
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
FROM cerc/trashscan-explorer-base:local
|
||||||
|
|
||||||
|
COPY ./scripts/start-explorer.sh /scripts/
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||||
|
CMD nc -z localhost 5000 || exit 1
|
||||||
|
|
||||||
|
CMD ["/scripts/start-explorer.sh"]
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
# Multi-stage build for TrashScan Explorer - Base image
|
||||||
|
# Stage 1: Build
|
||||||
|
FROM node:20-bullseye-slim AS builder
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
python3 \
|
||||||
|
make \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Stage 2: Production runtime
|
||||||
|
FROM node:20-bullseye-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
netcat-openbsd \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/package*.json ./
|
||||||
|
# Install production deps + vite (needed for server runtime even in prod due to module import structure)
|
||||||
|
RUN npm ci --omit=dev && npm install vite
|
||||||
|
|
||||||
|
COPY --from=builder /app/dist ./dist
|
||||||
|
|
||||||
|
EXPOSE 5000
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# Build the TrashScan Explorer image
|
||||||
|
source ${CERC_CONTAINER_BASE_DIR}/build-base.sh
|
||||||
|
|
||||||
|
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
|
# Two-stage build: base image from repo, final image with local scripts
|
||||||
|
docker build -t cerc/trashscan-explorer-base:local \
|
||||||
|
${build_command_args} \
|
||||||
|
-f ${SCRIPT_DIR}/Dockerfile.base \
|
||||||
|
${CERC_REPO_BASE_DIR}/TrashScan-Explorer
|
||||||
|
|
||||||
|
if [[ $? -ne 0 ]]; then
|
||||||
|
echo "FATAL: Base container build failed, exiting"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker build -t cerc/trashscan-explorer:local \
|
||||||
|
${build_command_args} \
|
||||||
|
-f ${SCRIPT_DIR}/Dockerfile \
|
||||||
|
${SCRIPT_DIR}
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -n "$CERC_SCRIPT_DEBUG" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "TrashScan Explorer starting..."
|
||||||
|
|
||||||
|
# Wait for database to be ready
|
||||||
|
if [ -n "$DATABASE_URL" ]; then
|
||||||
|
echo "Waiting for database to be ready..."
|
||||||
|
|
||||||
|
# Parse DATABASE_URL: postgres://user:pass@host:port/db
|
||||||
|
DB_HOST=$(echo $DATABASE_URL | sed -e 's|.*@||' -e 's|:.*||' -e 's|/.*||')
|
||||||
|
DB_PORT=$(echo $DATABASE_URL | sed -e 's|.*@[^:]*:||' -e 's|/.*||')
|
||||||
|
|
||||||
|
if [ -z "$DB_PORT" ] || [ "$DB_PORT" = "$DB_HOST" ]; then
|
||||||
|
DB_PORT=5432
|
||||||
|
fi
|
||||||
|
|
||||||
|
timeout=60
|
||||||
|
counter=0
|
||||||
|
until nc -z "$DB_HOST" "$DB_PORT" 2>/dev/null; do
|
||||||
|
counter=$((counter + 1))
|
||||||
|
if [ $counter -ge $timeout ]; then
|
||||||
|
echo "Error: Database not available after ${timeout} seconds"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Waiting for database at ${DB_HOST}:${DB_PORT}... ($counter/$timeout)"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Database is available!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run database migrations if needed
|
||||||
|
if [ "${RUN_MIGRATIONS:-true}" = "true" ]; then
|
||||||
|
echo "Running database migrations..."
|
||||||
|
npm run db:push 2>/dev/null || echo "No migration script found or migration failed, continuing..."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
echo "Starting TrashScan Explorer on port ${PORT:-5000}..."
|
||||||
|
exec node dist/index.js
|
||||||
|
|
@ -60,3 +60,4 @@ cerc/nitro-rpc-client
|
||||||
cerc/watcher-merkl-sushiswap-v3
|
cerc/watcher-merkl-sushiswap-v3
|
||||||
cerc/watcher-sushiswap-v3
|
cerc/watcher-sushiswap-v3
|
||||||
cerc/uniswap-interface
|
cerc/uniswap-interface
|
||||||
|
cerc/trashscan-explorer
|
||||||
|
|
|
||||||
|
|
@ -45,3 +45,4 @@ ponder
|
||||||
ipld-eth-server-payments
|
ipld-eth-server-payments
|
||||||
merkl-sushiswap-v3
|
merkl-sushiswap-v3
|
||||||
sushiswap-v3
|
sushiswap-v3
|
||||||
|
trashscan-explorer
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,4 @@ github.com/cerc-io/ponder
|
||||||
github.com/cerc-io/merkl-sushiswap-v3-watcher-ts
|
github.com/cerc-io/merkl-sushiswap-v3-watcher-ts
|
||||||
github.com/cerc-io/sushiswap-v3-watcher-ts
|
github.com/cerc-io/sushiswap-v3-watcher-ts
|
||||||
github.com/cerc-io/uniswap-interface
|
github.com/cerc-io/uniswap-interface
|
||||||
|
github.com/gorbagana-dev/TrashScan-Explorer
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,99 @@
|
||||||
|
# TrashScan Explorer Stack
|
||||||
|
|
||||||
|
TrashScan is a blockchain explorer for Gorbagana mainnet (Solana fork).
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Setup repositories (clones TrashScan-Explorer to ~/cerc/)
|
||||||
|
laconic-so --stack trashscan-explorer setup-repositories
|
||||||
|
|
||||||
|
# 2. Build containers
|
||||||
|
laconic-so --stack trashscan-explorer build-containers
|
||||||
|
|
||||||
|
# 3. Deploy
|
||||||
|
laconic-so --stack trashscan-explorer deploy-system up
|
||||||
|
|
||||||
|
# 4. Verify
|
||||||
|
docker ps --filter "name=trashscan"
|
||||||
|
curl http://localhost:5001/
|
||||||
|
|
||||||
|
# 5. View logs
|
||||||
|
laconic-so --stack trashscan-explorer deploy-system logs -f
|
||||||
|
|
||||||
|
# 6. Stop
|
||||||
|
laconic-so --stack trashscan-explorer deploy-system down
|
||||||
|
```
|
||||||
|
|
||||||
|
## Access
|
||||||
|
|
||||||
|
After deployment, access the explorer at: **http://localhost:5001**
|
||||||
|
|
||||||
|
Note: Default port is 5001 to avoid conflict with macOS AirPlay Receiver on port 5000.
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
| Service | Image | Port | Description |
|
||||||
|
|---------|-------|------|-------------|
|
||||||
|
| trashscan-explorer | cerc/trashscan-explorer:local | 5001 | React/Express blockchain explorer |
|
||||||
|
| trashscan-db | postgres:14-alpine | (internal) | PostgreSQL database |
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Environment variables can be set in your deployment configuration:
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|----------|---------|-------------|
|
||||||
|
| NODE_ENV | production | Node environment |
|
||||||
|
| DATABASE_URL | postgres://trashscan:password@trashscan-db:5432/trashscan | Database connection string |
|
||||||
|
| TRASHSCAN_HOST_PORT | 5001 | Host port for explorer |
|
||||||
|
| SESSION_SECRET | change-me-in-production | Express session secret |
|
||||||
|
| RPC_URL | https://rpc.trashscan.io/ | Gorbagana RPC endpoint |
|
||||||
|
| RUN_MIGRATIONS | true | Run database migrations on startup |
|
||||||
|
|
||||||
|
## External Dependencies
|
||||||
|
|
||||||
|
The explorer connects to the Gorbagana RPC at https://rpc.trashscan.io/ by default.
|
||||||
|
|
||||||
|
## Files in This Stack
|
||||||
|
|
||||||
|
```
|
||||||
|
stack-orchestrator/stack_orchestrator/data/
|
||||||
|
├── stacks/trashscan-explorer/
|
||||||
|
│ ├── stack.yml # Stack definition
|
||||||
|
│ └── README.md # This file
|
||||||
|
├── container-build/cerc-trashscan-explorer/
|
||||||
|
│ ├── Dockerfile.base # Multi-stage build (base)
|
||||||
|
│ ├── Dockerfile # Final image with scripts
|
||||||
|
│ ├── build.sh # Build script
|
||||||
|
│ └── scripts/
|
||||||
|
│ └── start-explorer.sh # Container startup script
|
||||||
|
└── compose/
|
||||||
|
└── docker-compose-trashscan-explorer.yml # Docker Compose
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification Checklist
|
||||||
|
|
||||||
|
After deployment, verify:
|
||||||
|
|
||||||
|
- [ ] `docker ps` shows both containers as `(healthy)`
|
||||||
|
- [ ] `curl http://localhost:5001/` returns HTTP 200
|
||||||
|
- [ ] Logs show "TrashScan Explorer starting..." and "Database is available!"
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Port 5000 conflict (macOS)
|
||||||
|
macOS AirPlay Receiver uses port 5000. This stack defaults to 5001.
|
||||||
|
To use a different port: `export TRASHSCAN_HOST_PORT=8080`
|
||||||
|
|
||||||
|
### Missing assets error during build
|
||||||
|
The upstream TrashScan-Explorer repo may be missing the `attached_assets/` directory.
|
||||||
|
Create placeholder images if needed:
|
||||||
|
```bash
|
||||||
|
cd ~/cerc/TrashScan-Explorer
|
||||||
|
mkdir -p attached_assets
|
||||||
|
# Create placeholder images for any missing assets
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Cannot find package 'vite'" error
|
||||||
|
The Dockerfile.base includes vite in production deps to handle this.
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
version: "1.0"
|
||||||
|
name: trashscan-explorer
|
||||||
|
description: "TrashScan blockchain explorer for Gorbagana mainnet"
|
||||||
|
repos:
|
||||||
|
- github.com/gorbagana-dev/TrashScan-Explorer
|
||||||
|
containers:
|
||||||
|
- cerc/trashscan-explorer
|
||||||
|
pods:
|
||||||
|
- trashscan-explorer
|
||||||
Loading…
Reference in New Issue