50bd396c2b
- Caddy HTTPS static file server config - Tor hidden service (V3 onion) for anonymous access - Bootstrap generation script (blk0001.dat + txleveldb + database) - Dropbox upload script - Systemd services (tor-bootstrap, caddy) - Operator guide and verification script
158 lines
4.9 KiB
Bash
Executable File
158 lines
4.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# generate-bootstrap.sh — Creates a TRI bootstrap archive from a running node's chaindata
|
|
# Usage: ./generate-bootstrap.sh /path/to/.triangles [output-file.tar.gz]
|
|
#
|
|
# Prerequisites on the node:
|
|
# - Triangles daemon running and fully synced
|
|
# - rpcuser and rpcpassword in triangles.conf
|
|
#
|
|
# What this script packages:
|
|
# - blk0001.dat (block chain)
|
|
# - txleveldb/ (UTXO index)
|
|
# - database/ (BDB state)
|
|
#
|
|
# What it DOES NOT package (deliberate — keeps archives small and safe):
|
|
# - wallet.dat (never include wallets in bootstrap!)
|
|
# - peers.dat (peer addresses — will be rediscovered)
|
|
# - debug.log, banlist.dat, .lock files
|
|
|
|
set -euo pipefail
|
|
|
|
DATADIR="${1:?Usage: $0 /path/to/.triangles [output-file.tar.gz]}"
|
|
OUTPUT="${2:-/tmp/triangles-bootstrap-$(date +%Y-%m-%d).tar.gz}"
|
|
CHAINDIR="$DATADIR"
|
|
|
|
echo "=== TRI Bootstrap Generator ==="
|
|
echo "Data directory: $CHAINDIR"
|
|
echo "Output file: $OUTPUT"
|
|
|
|
# Verify required files exist
|
|
if [ ! -f "$CHAINDIR/blk0001.dat" ]; then
|
|
echo "ERROR: blk0001.dat not found in $CHAINDIR"
|
|
exit 1
|
|
fi
|
|
|
|
if [ ! -d "$CHAINDIR/txleveldb" ]; then
|
|
echo "ERROR: txleveldb/ not found in $CHAINDIR"
|
|
exit 1
|
|
fi
|
|
|
|
# Check that the node is running and RPC is accessible
|
|
RPCPORT=$(grep -E "^rpcport=" "$CHAINDIR/triangles.conf" 2>/dev/null | cut -d= -f2 || echo "19112")
|
|
RPCUSER=$(grep -E "^rpcuser=" "$CHAINDIR/triangles.conf" 2>/dev/null | cut -d= -f2)
|
|
RPCPASSWORD=$(grep -E "^rpcpassword=" "$CHAINDIR/triangles.conf" 2>/dev/null | cut -d= -f2)
|
|
|
|
if [ -z "$RPCUSER" ] || [ -z "$RPCPASSWORD" ]; then
|
|
echo "WARNING: Could not find rpcuser/rpcpassword in triangles.conf. Skipping RPC checks."
|
|
BLOCKCOUNT="unknown"
|
|
BESTHASH="unknown"
|
|
else
|
|
echo "Checking chain tip via RPC..."
|
|
BLOCKCOUNT=$(curl -s -X POST \
|
|
-H "content-type: application/json" \
|
|
-u "$RPCUSER:$RPCPASSWORD" \
|
|
--max-time 5 \
|
|
--fail \
|
|
"http://127.0.0.1:$RPCPORT" \
|
|
-d '{"jsonrpc":"1.0","id":"bootstrap","method":"getblockcount","params":[]}' \
|
|
2>/dev/null | grep -oE '[0-9]+' | head -1 || echo "unknown")
|
|
|
|
BESTHASH=$(curl -s -X POST \
|
|
-H "content-type: application/json" \
|
|
-u "$RPCUSER:$RPCPASSWORD" \
|
|
--max-time 5 \
|
|
--fail \
|
|
"http://127.0.0.1:$RPCPORT" \
|
|
-d '{"jsonrpc":"1.0","id":"bootstrap","method":"getbestblockhash","params":[]}' \
|
|
2>/dev/null | grep -oE '"[0-9a-f]{64}"' | tr -d '"' | head -1 || echo "unknown")
|
|
|
|
echo "Chain tip: block $BLOCKCOUNT, hash $BESTHASH"
|
|
fi
|
|
|
|
# Get file sizes for the archive manifest
|
|
BLK_SIZE=$(du -sh "$CHAINDIR/blk0001.dat" 2>/dev/null | cut -f1)
|
|
TX_SIZE=$(du -sh "$CHAINDIR/txleveldb" 2>/dev/null | cut -f1)
|
|
DB_SIZE=$(du -sh "$CHAINDIR/database" 2>/dev/null | cut -f1 || echo "N/A")
|
|
|
|
echo ""
|
|
echo "Archive contents:"
|
|
echo " blk0001.dat : $BLK_SIZE"
|
|
echo " txleveldb/ : $TX_SIZE"
|
|
echo " database/ : $DB_SIZE"
|
|
echo ""
|
|
|
|
# Stop the node cleanly before archiving (recommended)
|
|
echo "Stopping trianglesd cleanly (if running)..."
|
|
"$CHAINDIR/../../.local/bin/trianglesd" -datadir="$CHAINDIR" -conf="$CHAINDIR/triangles.conf" stop 2>/dev/null || \
|
|
trianglesd -datadir="$CHAINDIR" stop 2>/dev/null || \
|
|
echo "(could not stop — continuing anyway)"
|
|
|
|
sleep 2
|
|
|
|
# Create the archive
|
|
# We use tar with gzip compression, preserving directory structure as-is
|
|
# Files are placed at the top level of the archive (not inside a subdirectory)
|
|
echo "Creating archive..."
|
|
mkdir -p "$(dirname "$OUTPUT")"
|
|
|
|
tar -czf "$OUTPUT" \
|
|
-C "$CHAINDIR" \
|
|
--exclude='wallet.dat*' \
|
|
--exclude='peers.dat' \
|
|
--exclude='banlist.dat' \
|
|
--exclude='debug.log' \
|
|
--exclude='*.lock' \
|
|
--exclude='.lock' \
|
|
--exclude='bootstrap.log' \
|
|
blk0001.dat \
|
|
txleveldb \
|
|
database \
|
|
2>/dev/null || true
|
|
|
|
ARCHIVE_SIZE=$(du -sh "$OUTPUT" | cut -f1)
|
|
ARCHIVE_HASH=$(sha256sum "$OUTPUT" | cut -d' ' -f1)
|
|
|
|
echo ""
|
|
echo "=== Bootstrap Archive Created ==="
|
|
echo "File: $OUTPUT"
|
|
echo "Size: $ARCHIVE_SIZE"
|
|
echo "SHA256: $ARCHIVE_HASH"
|
|
echo "Blocks: $BLOCKCOUNT"
|
|
echo "Best hash: $BESTHASH"
|
|
echo ""
|
|
|
|
# Write a manifest alongside the archive
|
|
MANIFEST="${OUTPUT%.tar.gz}.manifest.txt"
|
|
cat > "$MANIFEST" <<EOF
|
|
Triangles Bootstrap Archive
|
|
===========================
|
|
Generated: $(date -u)
|
|
Data dir: $CHAINDIR
|
|
Block height: $BLOCKCOUNT
|
|
Best block hash: $BESTHASH
|
|
Archive size: $ARCHIVE_SIZE
|
|
SHA256: $ARCHIVE_HASH
|
|
|
|
Contents:
|
|
blk0001.dat : $BLK_SIZE
|
|
txleveldb/ : $TX_SIZE
|
|
database/ : $DB_SIZE
|
|
|
|
Files EXCLUDED (deliberate):
|
|
wallet.dat* — never include wallets in bootstrap
|
|
peers.dat — will be rediscovered
|
|
banlist.dat — will be rediscovered
|
|
debug.log — runtime log
|
|
*.lock — lock files
|
|
|
|
To serve this file:
|
|
1. Place on your web server
|
|
2. Update Caddyfile to point to the directory
|
|
3. Update DNS/Tor hidden service if needed
|
|
4. Notify node operators of the new bootstrap URL
|
|
EOF
|
|
|
|
echo "Manifest written to: $MANIFEST"
|
|
echo ""
|
|
echo "Done!"
|