Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9bdb1b21b1 | |||
| 309f529218 | |||
| af55bfac80 | |||
| 372b252294 | |||
| 6c56e41e82 | |||
| 79b0c4a176 | |||
| 3db537d759 | |||
| 63be053b1d | |||
| d0fb2dc105 | |||
| bea3c4447c | |||
| 89a480a85a |
@@ -13,9 +13,13 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -55,9 +59,13 @@ jobs:
|
||||
# and BDB until they're fixed file-by-file.
|
||||
SAN_FLAGS: "-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=undefined -fno-sanitize=alignment,signed-integer-overflow,vptr"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
@@ -91,9 +99,14 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
shell: bash
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
@@ -244,9 +257,14 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
shell: bash
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
@@ -309,9 +327,13 @@ jobs:
|
||||
build-linux-qt:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
|
||||
- name: Set VERSION
|
||||
run: |
|
||||
@@ -428,9 +450,13 @@ jobs:
|
||||
build-linux-daemon:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
|
||||
- name: Set VERSION
|
||||
run: |
|
||||
@@ -560,9 +586,13 @@ jobs:
|
||||
build-macos:
|
||||
runs-on: macos-15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Checkout (with history for submodule)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Init submodules
|
||||
run: git submodule update --init --recursive
|
||||
|
||||
- name: Set VERSION
|
||||
run: |
|
||||
|
||||
@@ -71,3 +71,10 @@ triangles.conf
|
||||
*.o
|
||||
src/trianglesd
|
||||
src/obj/
|
||||
build-bench/
|
||||
build-cmake/
|
||||
build-cmake-test/
|
||||
build-latest/
|
||||
build-rocks-probe/
|
||||
build-rocksdb/
|
||||
bench-results.csv
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Sami Ahmed <tweet@sami-ahmed.net> Sami <sami@dashcaddy.net>
|
||||
Sami Ahmed <tweet@sami-ahmed.net> SamiAhmed7777 <sami@users.noreply.github.com>
|
||||
Sami Ahmed <tweet@sami-ahmed.net> SamiAhmed7777 <79177212+SamiAhmed7777@users.noreply.github.com>
|
||||
Sami Ahmed <tweet@sami-ahmed.net> Sami Ahmed <hello@sami-ahmed.net>
|
||||
Sami Ahmed <tweet@sami-ahmed.net> Sami Ahmed <samiahmed7777@gmail.com>
|
||||
+1
-1
@@ -6,7 +6,7 @@ if(POLICY CMP0167)
|
||||
endif()
|
||||
|
||||
project(Triangles
|
||||
VERSION 6.0.0
|
||||
VERSION 6.0.1
|
||||
DESCRIPTION "Cryptographic Triangles Wallet"
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
# TRI v6 Development Task Queue
|
||||
|
||||
*Autonomous development pipeline — Krystie cycles through these continuously.*
|
||||
|
||||
## Legend
|
||||
- **P0** = Critical (chain broken / users blocked)
|
||||
- **P1** = Important (v6 milestone)
|
||||
- **P2** = Nice-to-have (polish / optimization)
|
||||
- **Status**: TODO | IN-PROGRESS | DONE | BLOCKED
|
||||
|
||||
---
|
||||
|
||||
## P0 — Immediate (Unblock Chain & Users)
|
||||
|
||||
### T001: Fix DNS2 RPC thread crash
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: ThreadRPCServer exits on bad auth attempts from external IPs. Need to not kill the RPC thread on individual auth failures.
|
||||
- **Files**: `src/rpc.cpp` or `src/bitcoinrpc.cpp`
|
||||
- **Acceptance**: RPC stays up even with bad auth attempts; curl JSON-RPC works reliably
|
||||
- **Model**: Claude Code or MiniMax M2.7
|
||||
|
||||
### T002: Fix DNS2 wallet 0 confirmed balance
|
||||
- **Status**: TODO
|
||||
- **Depends**: T001 (need reliable RPC)
|
||||
- **Description**: Wallet restored from April 20 backup. Shows 11.24 TRI unconfirmed. Need to verify rescan completes and coins mature (520 confirmations) for staking.
|
||||
- **Files**: wallet.dat, `src/wallet.cpp`
|
||||
- **Acceptance**: Wallet shows confirmed balance after rescan + confirmations
|
||||
- **Model**: Krystie (manual investigation, not subagent)
|
||||
|
||||
### T003: Fix seeds.txt parsing (only returns 1 address)
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: HTTPS fetch of seeds.cryptographic-triangles.org/seeds.txt only returns 1 address. Possible comment parsing bug in net.cpp seed fetch logic.
|
||||
- **Files**: `src/net.cpp`, `/var/www/seeds/seeds.txt`
|
||||
- **Acceptance**: All 7 onion addresses returned on fetch
|
||||
- **Model**: ZAI GLM-5.1
|
||||
|
||||
### T004: Fix Sami's PC wallet block 570 stall
|
||||
- **Status**: IN-PROGRESS
|
||||
- **Depends**: Windows binary build (DONE — built on sami-pc)
|
||||
- **Description**: Windows Qt wallet stuck at block 570. GUI bootstrap fix committed (d0fb2dc). New binary built at E:\repos\triangles_v5\build-mingw\bin\triangles-qt.exe. Needs testing.
|
||||
- **Acceptance**: Windows wallet syncs past block 570 with bootstrap
|
||||
- **Model**: Krystie (manual deployment)
|
||||
|
||||
---
|
||||
|
||||
## P1 — v6 Core Milestones
|
||||
|
||||
### T010: Complete RocksDB runtime testing
|
||||
- **Status**: TODO
|
||||
- **Depends**: T001
|
||||
- **Description**: RocksDB backend compiles clean but never tested with actual blockchain data. Need to: start daemon with `-rocksdb`, let it index chain, verify block lookups work, compare performance vs LevelDB.
|
||||
- **Files**: `src/txdb.h`, `src/txdb.cpp`, `src/utxosnapshot.cpp`
|
||||
- **Acceptance**: Daemon runs with `-rocksdb` flag, processes blocks, RPC queries return correct data
|
||||
- **Model**: MiniMax M2.7
|
||||
|
||||
### T011: Wire UTXO snapshot P2P distribution (SnapshotNet)
|
||||
- **Status**: TODO
|
||||
- **Depends**: T010
|
||||
- **Description**: `snapshotnet.cpp` exists but is placeholder. Need to implement: peer advertisement of snapshot availability, chunk transfer protocol, hash verification, integration with bootstrap flow.
|
||||
- **Files**: `src/snapshotnet.cpp`, `src/net.cpp`, `src/utxosnapshot.cpp`
|
||||
- **Acceptance**: New node can get UTXO snapshot from peers via P2P (not just HTTPS)
|
||||
- **Model**: Claude Code + MiniMax M2.7 (architecture + implementation)
|
||||
|
||||
### T012: Implement automated checkpoint generation (DESIGN DONE)
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: Checkpoints exist through block 2,207,000 but are manually maintained. Need automated checkpoint generation: every N blocks, compute checkpoint hash, push to code or external manifest.
|
||||
- **Files**: `src/checkpoints.cpp`, `src/checkpoints.h`
|
||||
- **Acceptance**: New checkpoints generated automatically, committed or published
|
||||
- **Model**: Claude Code
|
||||
|
||||
### T013: GPG signing for bootstrap artifacts
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: GPG key created (6913E13610F698183429CE20C2DC60618C85A159). Need to: sign every bootstrap/snapshot artifact on generation, verify signature on download, publish public key.
|
||||
- **Files**: `/usr/local/bin/auto-update.sh`, `src/bootstrap.cpp`
|
||||
- **Acceptance**: `gpg --verify` works on downloaded artifacts
|
||||
- **Model**: ZAI GLM-5.1
|
||||
|
||||
### T014: Contabo seed Docker image hardening
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: Seeds are running but image is fragile. Need: proper Dockerfile with version pinning, health checks, auto-restart, log shipping, and persistent volumes.
|
||||
- **Files**: `/tmp/Dockerfile` on Contabo, `/tri/seed-{1..4}/`
|
||||
- **Acceptance**: Seeds survive host reboot, auto-restart on crash, health check endpoint
|
||||
- **Model**: ZAI GLM-5.1
|
||||
|
||||
### T015: Network health dashboard
|
||||
- **Status**: TODO
|
||||
- **Depends**: T001, T003
|
||||
- **Description**: Operator-facing dashboard showing: block height per node, peer count, staking weight, chain sync status, seed health. Could be a simple web page served from DNS2.
|
||||
- **Files**: New — `src/rpcblockchain.cpp` (health endpoint), frontend
|
||||
- **Acceptance**: Live page showing all 7 nodes' status updated every 30s
|
||||
- **Model**: MiniMax M2.7 (design) + Claude Code (implementation)
|
||||
|
||||
### T016: Hetzner ARM64 persistent setup
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: Hetzner node is running but manually configured. Need: systemd service, auto-start on boot, bootstrap automation, monitoring.
|
||||
- **Files**: systemd unit file on Hetzner
|
||||
- **Acceptance**: Node survives reboot, auto-syncs, reports health
|
||||
- **Model**: Krystie (manual, it's infra not code)
|
||||
|
||||
---
|
||||
|
||||
## P2 — Polish & Optimization
|
||||
|
||||
### T020: Remove unused Gemini/Google references from codebase
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: Clean up any dead code, unused imports, stale comments referencing old architectures.
|
||||
- **Model**: ZAI GLM-5.1
|
||||
|
||||
### T021: Comprehensive test suite
|
||||
- **Status**: TODO
|
||||
- **Depends**: T010
|
||||
- **Description**: Expand test coverage for: UTXO snapshot load/dump, RocksDB backend, bootstrap download, seed fetch, checkpoint verification.
|
||||
- **Files**: `src/test/`
|
||||
- **Acceptance**: `test_triangles` passes with < 5 pre-existing failures
|
||||
- **Model**: ZAI GLM-5.1 + MiniMax M2.7
|
||||
|
||||
### T022: CI/CD pipeline for releases
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: GitHub Actions workflow: on tag push, build Linux x86_64 + ARM64 + Windows, create release with all binaries + checksums.
|
||||
- **Files**: `.github/workflows/build-all.yml`
|
||||
- **Acceptance**: Tag push produces release with 3 platform binaries
|
||||
- **Model**: ZAI GLM-5.1
|
||||
|
||||
### T023: TRIdock + tri-wallet-web consolidation
|
||||
- **Status**: TODO
|
||||
- **Depends**: none
|
||||
- **Description**: TRIdock and tri-wallet-web appear to be near-duplicates. Evaluate and either consolidate or clearly separate concerns.
|
||||
- **Model**: MiniMax M2.7 (analysis)
|
||||
|
||||
---
|
||||
|
||||
## Completed
|
||||
|
||||
### ✅ Windows GUI bootstrap fix (d0fb2dc)
|
||||
- Removed `#ifndef QT_GUI` guard so auto-bootstrap runs in GUI wallet
|
||||
- Added `uiInterface.InitMessage()` for progress display
|
||||
|
||||
### ✅ Windows native build on sami-pc
|
||||
- Built `triangles-qt.exe` (26MB) and `trianglesd.exe` via MSYS2/MinGW64
|
||||
- All dependencies found natively
|
||||
|
||||
### ✅ RocksDB integration complete (ac9c6fb)
|
||||
- CActiveTxDB wrapper, dual-backend support, compiles clean
|
||||
|
||||
### ✅ All nodes updated to v5.9.7.0
|
||||
- DNS2, DNS3, Hetzner, Contabo seeds all running latest
|
||||
|
||||
### ✅ Bootstrap infrastructure live
|
||||
- HTTPS at bootstrap.cryptographic-triangles.org
|
||||
- Tor hidden service serving nginx on port 8085
|
||||
- Seeds.txt with 7 onion nodes
|
||||
Executable
+210
@@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Fresh-datadir IBD smoke test for TRI.
|
||||
# Goal: detect the classic "starts from zero but stalls early / loops around 570"
|
||||
# failure mode, and verify that sync keeps making forward progress.
|
||||
#
|
||||
# Example:
|
||||
# bash scripts/ibd-smoke-test.sh \
|
||||
# --bin ./build/src/trianglesd \
|
||||
# --bootstrap-url http://100.104.4.5:8085/triangles-bootstrap.tar.gz \
|
||||
# --addnode 74.208.167.19 --addnode 194.233.88.206
|
||||
|
||||
BIN="${BIN:-./build/src/trianglesd}"
|
||||
TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-1800}" # 30 minutes target window
|
||||
POLL_SECONDS="${POLL_SECONDS:-15}"
|
||||
STALL_WINDOW_SECONDS="${STALL_WINDOW_SECONDS:-180}"
|
||||
BOOTSTRAP_URL="${BOOTSTRAP_URL:-}"
|
||||
WORKDIR="${WORKDIR:-}"
|
||||
RPC_PORT="${RPC_PORT:-19192}"
|
||||
P2P_PORT="${P2P_PORT:-24193}"
|
||||
MIN_EXPECTED_HEIGHT="${MIN_EXPECTED_HEIGHT:-5000}"
|
||||
ALLOW_IBD="${ALLOW_IBD:-0}"
|
||||
WHITELIST="${WHITELIST:-127.0.0.1}"
|
||||
ADDNODES=()
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $0 [options]
|
||||
|
||||
Options:
|
||||
--bin PATH trianglesd binary (default: $BIN)
|
||||
--bootstrap-url URL optional bootstrap tar.gz URL to preload
|
||||
--workdir PATH use an explicit temp workdir
|
||||
--rpc-port N RPC port for test node (default: $RPC_PORT)
|
||||
--p2p-port N P2P port for test node (default: $P2P_PORT)
|
||||
--timeout N total test timeout seconds (default: $TIMEOUT_SECONDS)
|
||||
--poll N poll interval seconds (default: $POLL_SECONDS)
|
||||
--stall-window N no-progress failure window seconds (default: $STALL_WINDOW_SECONDS)
|
||||
--min-height N minimum expected height/progress floor (default: $MIN_EXPECTED_HEIGHT)
|
||||
--allow-ibd allow test to pass while still in IBD if progress is strong
|
||||
--addnode HOST trusted peer to add (repeatable)
|
||||
-h, --help show this help
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--bin) BIN="$2"; shift 2 ;;
|
||||
--bootstrap-url) BOOTSTRAP_URL="$2"; shift 2 ;;
|
||||
--workdir) WORKDIR="$2"; shift 2 ;;
|
||||
--rpc-port) RPC_PORT="$2"; shift 2 ;;
|
||||
--p2p-port) P2P_PORT="$2"; shift 2 ;;
|
||||
--timeout) TIMEOUT_SECONDS="$2"; shift 2 ;;
|
||||
--poll) POLL_SECONDS="$2"; shift 2 ;;
|
||||
--stall-window) STALL_WINDOW_SECONDS="$2"; shift 2 ;;
|
||||
--min-height) MIN_EXPECTED_HEIGHT="$2"; shift 2 ;;
|
||||
--allow-ibd) ALLOW_IBD=1; shift ;;
|
||||
--addnode) ADDNODES+=("$2"); shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "unknown arg: $1" >&2; usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ ! -x "$BIN" ]]; then
|
||||
echo "ERROR: trianglesd binary not executable: $BIN" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [[ -z "$WORKDIR" ]]; then
|
||||
WORKDIR="$(mktemp -d /tmp/tri-ibd-smoke-XXXXXX)"
|
||||
fi
|
||||
DATADIR="$WORKDIR/datadir"
|
||||
mkdir -p "$DATADIR"
|
||||
|
||||
RPCUSER="tri_test"
|
||||
RPCPASSWORD="tri_test_$(date +%s)_$RANDOM"
|
||||
CONF="$DATADIR/triangles.conf"
|
||||
cat > "$CONF" <<EOF
|
||||
server=1
|
||||
daemon=1
|
||||
staking=0
|
||||
listen=1
|
||||
discover=0
|
||||
upnp=0
|
||||
tor=0
|
||||
irc=0
|
||||
dnsseed=1
|
||||
checkpoints=1
|
||||
rpcuser=$RPCUSER
|
||||
rpcpassword=$RPCPASSWORD
|
||||
rpcport=$RPC_PORT
|
||||
port=$P2P_PORT
|
||||
maxconnections=32
|
||||
whitelist=$WHITELIST
|
||||
logtimestamps=1
|
||||
EOF
|
||||
|
||||
for host in "${ADDNODES[@]}"; do
|
||||
echo "addnode=$host" >> "$CONF"
|
||||
done
|
||||
|
||||
cleanup() {
|
||||
"$BIN" -datadir="$DATADIR" -conf="$CONF" stop >/dev/null 2>&1 || true
|
||||
sleep 2 || true
|
||||
pkill -f "$DATADIR" >/dev/null 2>&1 || true
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ -n "$BOOTSTRAP_URL" ]]; then
|
||||
echo "[ibd-test] downloading bootstrap: $BOOTSTRAP_URL"
|
||||
curl -L --fail --max-time 1800 "$BOOTSTRAP_URL" -o "$WORKDIR/bootstrap.tar.gz"
|
||||
tar xzf "$WORKDIR/bootstrap.tar.gz" -C "$DATADIR"
|
||||
rm -f "$DATADIR/database/log."* "$DATADIR/txleveldb/LOCK" "$DATADIR/smsgDB/LOCK" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
echo "[ibd-test] starting node from datadir: $DATADIR"
|
||||
"$BIN" -daemon -datadir="$DATADIR" -conf="$CONF" >/dev/null
|
||||
sleep 6
|
||||
|
||||
rpc() {
|
||||
local method="$1"
|
||||
local params="${2:-[]}"
|
||||
curl -sS --fail --user "$RPCUSER:$RPCPASSWORD" \
|
||||
--data-binary "{\"jsonrpc\":\"1.0\",\"id\":\"ibd\",\"method\":\"$method\",\"params\":$params}" \
|
||||
-H 'content-type: text/plain;' "http://127.0.0.1:$RPC_PORT/"
|
||||
}
|
||||
|
||||
extract_json() {
|
||||
python3 -c 'import json,sys; obj=json.load(sys.stdin); print(obj["result"])'
|
||||
}
|
||||
|
||||
extract_field() {
|
||||
local field="$1"
|
||||
python3 -c 'import json,sys; obj=json.load(sys.stdin); val=obj["result"].get(sys.argv[1]); print(val if val is not None else "")' "$field"
|
||||
}
|
||||
|
||||
start_ts=$(date +%s)
|
||||
last_progress_ts=$start_ts
|
||||
last_height=-1
|
||||
samples=0
|
||||
same_570_loops=0
|
||||
best_height=0
|
||||
|
||||
while true; do
|
||||
now=$(date +%s)
|
||||
elapsed=$((now - start_ts))
|
||||
if (( elapsed > TIMEOUT_SECONDS )); then
|
||||
echo "FAIL: timeout after ${elapsed}s"
|
||||
break
|
||||
fi
|
||||
|
||||
if info_json="$(rpc getblockchaininfo 2>/dev/null)"; then
|
||||
height=$(printf '%s' "$info_json" | extract_field blocks)
|
||||
ibd=$(printf '%s' "$info_json" | extract_field initialblockdownload)
|
||||
headers=$(printf '%s' "$info_json" | extract_field headers)
|
||||
else
|
||||
height=""
|
||||
ibd=""
|
||||
headers=""
|
||||
fi
|
||||
|
||||
peers=0
|
||||
if peer_json="$(rpc getconnectioncount 2>/dev/null)"; then
|
||||
peers=$(printf '%s' "$peer_json" | extract_json)
|
||||
fi
|
||||
|
||||
if [[ -n "$height" && "$height" != "$last_height" ]]; then
|
||||
last_progress_ts=$now
|
||||
last_height="$height"
|
||||
if (( height > best_height )); then
|
||||
best_height=$height
|
||||
fi
|
||||
fi
|
||||
|
||||
log_file="$DATADIR/debug.log"
|
||||
if [[ -f "$log_file" ]]; then
|
||||
loop_hits=$(tail -n 400 "$log_file" | grep -c 'start=571' || true)
|
||||
if (( loop_hits >= 3 )); then
|
||||
same_570_loops=$loop_hits
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "[ibd-test] t=${elapsed}s height=${height:-?} headers=${headers:-?} ibd=${ibd:-?} peers=$peers best=$best_height"
|
||||
|
||||
if [[ -n "$height" ]] && (( best_height >= MIN_EXPECTED_HEIGHT )) && [[ "$ibd" == "False" || "$ibd" == "false" ]]; then
|
||||
echo "PASS: left IBD and reached height $best_height"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$ALLOW_IBD" == "1" && -n "$height" ]] && (( best_height >= MIN_EXPECTED_HEIGHT )); then
|
||||
echo "PASS: strong sync progress observed (height $best_height) even though IBD remains true"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if (( now - last_progress_ts > STALL_WINDOW_SECONDS )); then
|
||||
echo "FAIL: no block-height progress for $((now - last_progress_ts))s"
|
||||
if (( same_570_loops > 0 )); then
|
||||
echo "HINT: detected repeated start=571 loop pattern ($same_570_loops hits in recent log tail)"
|
||||
fi
|
||||
echo "--- debug tail ---"
|
||||
tail -n 120 "$log_file" 2>/dev/null || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
((samples++)) || true
|
||||
sleep "$POLL_SECONDS"
|
||||
done
|
||||
|
||||
exit 1
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
|
||||
#define CLIENT_VERSION_MAJOR 6
|
||||
#define CLIENT_VERSION_MINOR 0
|
||||
#define CLIENT_VERSION_REVISION 0
|
||||
#define CLIENT_VERSION_REVISION 1
|
||||
#define CLIENT_VERSION_BUILD 0
|
||||
|
||||
// Converts the parameter X to a string after macro replacement on X has been performed.
|
||||
|
||||
+25
-4
@@ -417,7 +417,7 @@ std::string HelpMessage()
|
||||
//" -proxy=<ip:port> " + _("Connect through socks proxy") + "\n" +
|
||||
//" -socks=<n> " + _("Select the version of socks proxy to use (4-5, default: 5)") + "\n" +
|
||||
" -tor=<ip:port> " + _("Use proxy to reach tor hidden services (default: same as -proxy)") + "\n"
|
||||
" -notor " + _("Disable Tor (WARNING: wallet will not start - Tor is required)") + "\n" +
|
||||
" -notor " + _("Disable Tor - run in clearnet-only mode (no .onion connectivity)") + "\n" +
|
||||
" -torsocks=<port> " + _("Set embedded or managed Tor SOCKS proxy port (default: 19099)") + "\n" +
|
||||
" -torhiddenservice " + _("Enable the managed Tor hidden service (default: 1)") + "\n" +
|
||||
" -torhsport=<port> " + _("Set embedded or managed Tor hidden service port (default: wallet listen port)") + "\n" +
|
||||
@@ -927,7 +927,8 @@ bool AppInit2()
|
||||
// v5.9.5: P2P UTXO snapshot fetch is the default for fresh installs (Step 11.6).
|
||||
// The legacy clearnet HTTP bootstrap only runs when the user explicitly requests
|
||||
// it via -bootstrap, or when -snapshot=0 disables the P2P fetcher.
|
||||
#ifndef QT_GUI
|
||||
// Bootstrap auto-download works for both GUI and daemon.
|
||||
// GUI users get the same automatic bootstrap on fresh installs.
|
||||
{
|
||||
bool wantsBootstrap = GetBoolArg("-bootstrap", false);
|
||||
bool noBootstrap = GetBoolArg("-nobootstrap", false);
|
||||
@@ -938,6 +939,7 @@ bool AppInit2()
|
||||
if (needsBootstrap && !noBootstrap && !snapshotMode) {
|
||||
printf("Bootstrap: no blockchain data found — downloading automatically.\n");
|
||||
printf("Bootstrap: (use -nobootstrap to skip)\n");
|
||||
uiInterface.InitMessage(_("Downloading blockchain data..."));
|
||||
wantsBootstrap = true;
|
||||
} else if (needsBootstrap && snapshotMode && !wantsBootstrap) {
|
||||
printf("Bootstrap: no blockchain data found — will fetch UTXO snapshot via P2P after network start.\n");
|
||||
@@ -951,13 +953,24 @@ bool AppInit2()
|
||||
std::string host = Bootstrap::DEFAULT_HOST;
|
||||
std::string strError;
|
||||
|
||||
auto progressFn = [](int64_t bytesDownloaded, int64_t totalBytes) {
|
||||
int64_t lastGuiUpdate = 0;
|
||||
auto progressFn = [&lastGuiUpdate](int64_t bytesDownloaded, int64_t totalBytes) {
|
||||
if (totalBytes > 0) {
|
||||
printf("\rBootstrap: %lld / %lld MB (%lld%%)",
|
||||
(long long)(bytesDownloaded / (1024*1024)),
|
||||
(long long)(totalBytes / (1024*1024)),
|
||||
(long long)((bytesDownloaded * 100) / totalBytes));
|
||||
fflush(stdout);
|
||||
// Update GUI status bar every ~1 MB
|
||||
int64_t now = GetTimeMillis();
|
||||
if (now - lastGuiUpdate > 1000) {
|
||||
lastGuiUpdate = now;
|
||||
std::string msg = strprintf("Downloading blockchain: %lld / %lld MB (%lld%%)",
|
||||
(long long)(bytesDownloaded / (1024*1024)),
|
||||
(long long)(totalBytes / (1024*1024)),
|
||||
(long long)((bytesDownloaded * 100) / totalBytes));
|
||||
uiInterface.InitMessage(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -999,7 +1012,6 @@ bool AppInit2()
|
||||
strprintf("host=%s success=%d utxo_snapshot=%d", host.c_str(), success, triedUtxoSnapshot));
|
||||
}
|
||||
} // end bootstrap scope
|
||||
#endif
|
||||
|
||||
// ********************************************************* Step 6c: manual UTXO snapshot loading
|
||||
// If utxo-snapshot.bin exists in data dir and the chain DB hasn't been
|
||||
@@ -1343,6 +1355,15 @@ bool AppInit2()
|
||||
#ifdef USE_UPNP
|
||||
fUseUPnP = false;
|
||||
#endif
|
||||
} else if (GetBoolArg("-notor", false)) {
|
||||
// -notor: user explicitly disabled Tor. Allow the daemon to start
|
||||
// in clearnet-only mode (useful for diagnostics, benchmarking, and
|
||||
// recovery). .onion connectivity will not be available.
|
||||
printf("NOTICE: Tor disabled via -notor. Running in clearnet-only mode.\n");
|
||||
printf(" .onion connections will NOT be available.\n");
|
||||
SetReachable(NET_IPV4, true);
|
||||
SetReachable(NET_IPV6, true);
|
||||
SetReachable(NET_TOR, false);
|
||||
} else {
|
||||
std::string torError = CTorEmbedded::GetInstance()->GetStartupError();
|
||||
if (torError.empty())
|
||||
|
||||
+28
-4
@@ -259,10 +259,34 @@ bool CTorProcess::WriteTorrc()
|
||||
// SOCKS proxy for wallet connections
|
||||
torrc << "SocksPort " << socksPort << "\n";
|
||||
|
||||
// Data directory for Tor state
|
||||
fs::path torStateDir = dataPath / "state";
|
||||
fs::create_directories(torStateDir);
|
||||
torrc << "DataDirectory " << torStateDir.string() << "\n";
|
||||
// Data directory for Tor state.
|
||||
// Use the tor_data directory itself as DataDirectory so that Tor creates
|
||||
// its internal 'state' FILE at <tor_data>/state. Older wallet builds
|
||||
// erroneously created a subdirectory called 'state' and pointed
|
||||
// DataDirectory at it; newer Tor versions (0.4.9+) reject that because
|
||||
// they expect to write a plain file called 'state' inside DataDirectory.
|
||||
//
|
||||
// Recovery: if 'state' exists as a directory, move its contents up and
|
||||
// remove it so that Tor can create its state file in the normal location.
|
||||
{
|
||||
fs::path badStateDir = dataPath / "state";
|
||||
if (fs::exists(badStateDir) && fs::is_directory(badStateDir)) {
|
||||
// Migrate any files inside the bad 'state/' directory up to dataPath
|
||||
try {
|
||||
for (auto& entry : fs::directory_iterator(badStateDir)) {
|
||||
fs::path dest = dataPath / entry.path().filename();
|
||||
if (!fs::exists(dest)) {
|
||||
fs::rename(entry.path(), dest);
|
||||
}
|
||||
}
|
||||
fs::remove(badStateDir);
|
||||
printf("Auto-recovered: removed legacy 'state' directory from %s\n", dataPath.string().c_str());
|
||||
} catch (const fs::filesystem_error& e) {
|
||||
printf("WARNING: Could not auto-recover tor_data/state directory: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
torrc << "DataDirectory " << dataPath.string() << "\n";
|
||||
|
||||
// Persistent Tor log for post-mortem debugging on user machines.
|
||||
fs::path torLogPath = dataPath / "tor.log";
|
||||
|
||||
+66
-34
@@ -546,10 +546,17 @@ int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRe
|
||||
bool HTTPAuthorized(map<string, string>& mapHeaders)
|
||||
{
|
||||
string strAuth = mapHeaders["authorization"];
|
||||
if (strAuth.substr(0,6) != "Basic ")
|
||||
if (strAuth.size() < 6 || strAuth.substr(0,6) != "Basic ")
|
||||
return false;
|
||||
string strUserPass64 = strAuth.substr(6); strUserPass64 = TrimString(strUserPass64);
|
||||
string strUserPass = DecodeBase64(strUserPass64);
|
||||
if (strUserPass64.empty())
|
||||
return false;
|
||||
string strUserPass;
|
||||
try {
|
||||
strUserPass = DecodeBase64(strUserPass64);
|
||||
} catch (const std::exception&) {
|
||||
return false;
|
||||
}
|
||||
return TimingResistantEqual(strUserPass, strRPCUserColonPass);
|
||||
}
|
||||
|
||||
@@ -783,44 +790,61 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor<Protocol,
|
||||
{
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]++;
|
||||
|
||||
// Immediately start accepting new connections, except when we're cancelled or our socket is closed.
|
||||
if (error != asio::error::operation_aborted
|
||||
&& acceptor->is_open())
|
||||
RPCListen(acceptor, context, fUseSSL);
|
||||
try {
|
||||
// Immediately start accepting new connections, except when we're cancelled or our socket is closed.
|
||||
if (error != asio::error::operation_aborted
|
||||
&& acceptor->is_open())
|
||||
RPCListen(acceptor, context, fUseSSL);
|
||||
|
||||
AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
|
||||
AcceptedConnectionImpl<ip::tcp>* tcp_conn = dynamic_cast< AcceptedConnectionImpl<ip::tcp>* >(conn);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error != asio::error::operation_aborted)
|
||||
printf("RPC accept error from %s: %s (%d)\n",
|
||||
tcp_conn ? tcp_conn->peer.address().to_string().c_str() : "unknown peer",
|
||||
error.message().c_str(),
|
||||
error.value());
|
||||
if (error)
|
||||
{
|
||||
if (error != asio::error::operation_aborted)
|
||||
printf("RPC accept error from %s: %s (%d)\n",
|
||||
tcp_conn ? tcp_conn->peer.address().to_string().c_str() : "unknown peer",
|
||||
error.message().c_str(),
|
||||
error.value());
|
||||
delete conn;
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
return;
|
||||
}
|
||||
|
||||
// Restrict callers by IP. It is important to
|
||||
// do this before starting client thread, to filter out
|
||||
// certain DoS and misbehaving clients.
|
||||
else if (tcp_conn
|
||||
&& !ClientAllowed(tcp_conn->peer.address()))
|
||||
{
|
||||
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
|
||||
try {
|
||||
if (!fUseSSL)
|
||||
conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
|
||||
} catch (const std::exception& e) {
|
||||
printf("RPC error sending 403 to %s: %s\n",
|
||||
tcp_conn->peer.address().to_string().c_str(), e.what());
|
||||
}
|
||||
delete conn;
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
return;
|
||||
}
|
||||
|
||||
// start HTTP client thread
|
||||
else if (!NewThread(ThreadRPCServer3, conn)) {
|
||||
printf("Failed to create RPC server client thread\n");
|
||||
delete conn;
|
||||
}
|
||||
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
} catch (std::exception& e) {
|
||||
PrintException(&e, "RPCAcceptHandler()");
|
||||
delete conn;
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
return;
|
||||
}
|
||||
|
||||
// Restrict callers by IP. It is important to
|
||||
// do this before starting client thread, to filter out
|
||||
// certain DoS and misbehaving clients.
|
||||
else if (tcp_conn
|
||||
&& !ClientAllowed(tcp_conn->peer.address()))
|
||||
{
|
||||
// Only send a 403 if we're not using SSL to prevent a DoS during the SSL handshake.
|
||||
if (!fUseSSL)
|
||||
conn->stream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush;
|
||||
} catch (...) {
|
||||
PrintException(NULL, "RPCAcceptHandler()");
|
||||
delete conn;
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
}
|
||||
|
||||
// start HTTP client thread
|
||||
else if (!NewThread(ThreadRPCServer3, conn)) {
|
||||
printf("Failed to create RPC server client thread\n");
|
||||
delete conn;
|
||||
}
|
||||
|
||||
vnThreadsRunning[THREAD_RPCLISTENER]--;
|
||||
}
|
||||
|
||||
void ThreadRPCServer2(void* parg)
|
||||
@@ -1128,6 +1152,7 @@ void ThreadRPCServer3(void* parg)
|
||||
AcceptedConnection *conn = (AcceptedConnection *) parg;
|
||||
|
||||
bool fRun = true;
|
||||
try {
|
||||
while (true)
|
||||
{
|
||||
if (fShutdown || !fRun)
|
||||
@@ -1247,6 +1272,13 @@ void ThreadRPCServer3(void* parg)
|
||||
}
|
||||
}
|
||||
|
||||
} // end try
|
||||
catch (std::exception& e) {
|
||||
PrintException(&e, "ThreadRPCServer3()");
|
||||
} catch (...) {
|
||||
PrintException(NULL, "ThreadRPCServer3()");
|
||||
}
|
||||
|
||||
delete conn;
|
||||
{
|
||||
LOCK(cs_THREAD_RPCHANDLER);
|
||||
|
||||
Reference in New Issue
Block a user