RocksDB 10.10.1 (pinned for v6.2.4) writes '-std=c++20' into its
installed rocksdb.pc Cflags. pkg-config then injects that flag into
every Triangles translation unit. C++ units ignore the redundant
flag, but C units (src/lz4/lz4.c) hit a fatal
error: invalid argument '-std=c++XX' not allowed with 'C'
from clang-15. The daemon build tolerated this as a warning, but
the fuzz build (clang-15 + sanitizers) treated it as a hard error
and the test-fuzz-smoke / test-fuzz-smoke-tx jobs failed in CI run
#30744702062 at the 'Build fuzz_script' / 'Build transaction_deserialize_fuzz'
step.
The previous fix only stripped '-std=c++17' (a relic of the 8.x pin).
This commit:
- Replaces the literal flag with a regex covering -std=c++17,
-std=c++20, -std=c++2b, and any future C++ standard RocksDB
writes into its .pc Cflags.
- Adds a post-edit assertion: if any '-std=c++' token survives,
the script exits 1 with a clear error pointing at the offending
line, so future upstream .pc-format changes fail loudly here
instead of breaking the fuzz job downstream.
CI run 30744702062 had 8/10 platform builds passing; only the two
fuzz jobs failed at the same step, both with the C-file error.
This is the v6.2.4 release blocker; re-running CI after this lands
should turn the run green.
Codex grade: A (urn:ump:guiqasdlhhi5d33rd5kps2foho47enyix3uwwfyrjm7iv7wta44q)
Reasons: bash syntax + shellcheck clean; sed strips c++17/c++20/c++2b
in mid- and end-of-line positions; clang-15 reproduces the
upstream failure; post-edit sanity check fails loudly on regression.
Per Sami directive 2026-08-02: 'why wouldn't we be using the latest
RocksDB?' Bumped CI to RocksDB 10.10.1 (commit
4595a5e95ae8525c42e172a054435782b3479c57, latest 10.x before 11.x line
began). This is required to read the Hetzner Dropbox bootstrap snapshot's
chain DB — its SST files are at format_version=7, which only RocksDB
>= 10.4.0 can open.
CoDEx flagged a previous proposal of 8.11.4 (wrong: 8.11.x only has
format_version=6 as default; v7 default arrived only in 10.11.0).
CoDEx also flagged an attempted explicit 'table_opts.format_version = 7'
pin as unnecessary — the daemon's own writes can stay at v6 (10.10.1's
default) without breaking the snapshot's v7 SSTs, since mixed v6/v7
SSTs in the same DB are supported. Reverted that pin; documented the
no-pin decision in CHANGELOG.md and inline in txdb-rocksdb.cpp.
src/txdb-rocksdb.cpp: kept RocksDB's own default (6 in 10.10.1) — no
explicit format_version pin. Comment explains why.
scripts/ci/build-rocksdb.sh: rocksdb 8.9.1 -> 10.10.1, commit pin
updated, stale 8.9.1 references in comments cleaned up. Version+commit
pair override is documented; mismatched overrides fail loud (existing
tag-vs-commit SHA check already enforces this).
CHANGELOG.md: v6.2.4 entry. Operator notes for upgrade from 6.2.3 cover:
- SONAME change librocksdb.so.8.9.1 -> librocksdb.so.10.10.1
- v7 SSTs from the imported snapshot make RocksDB < 10.4.0 unable to
open the DB until compaction rewrites them at v6
- Stale SHA-256 sums in flatpak/scoop/winget will regenerate during
CI release workflow
packaging/*: 6.2.3 -> 6.2.4 (deb, rpm, docker, flatpak, scoop, winget,
snap, appimage). Stale 8.9.1 references left in workflow comments
(build-all.yml, lint.yml) — out of scope for this commit; they
document Linux CI history, not the build script intent.
src/CMakeLists.txt: 8.9.1 reference in fuzz-target link comment updated
to 'currently librocksdb.so.10.10.1'.
src/clientversion.h: REVISION 3 -> 4 (full version: 6.2.4.0).
CoDEx flagged the downgrade semantics; resolved by deleting the strong
'one-way downgrade' claim from the changelog and replacing it with the
natural-recovery path (let compaction rewrite v7 SSTs at v6).
[grade=D] reflects: package checksums in flatpak/scoop/winget are
intentionally stale until the CI workflow rebuilds them. They MUST
NOT be packaged until regenerated. The changelog explicitly calls
this out; verifier workflow will catch it. CHANGELOG.md notes block
shipping those package manifests.
Five files for tri-pi cross-compilation and ARM64 Tor support:
- cmake/aarch64-toolchain.cmake: CMake toolchain file for aarch64-linux-gnu
- cmake/armhf-toolchain.cmake: same, for arm-linux-gnueabihf
- scripts/tri-pi-test.sh: QEMU-based test harness (user-mode + full-system)
for Pi 3B/3A+/4B/5. Runs the cross-compiled trianglesd under
qemu-aarch64-static so ARM binary correctness can be validated without
physical Pi hardware.
- src/tor/build-libtor-aarch64.sh: cross-compile libtor.a for aarch64
using the vendored configure flow from src/tor/configure.vendored.
These accompany the in-progress tri-pi bootstrap work (Hetzner Pi,
raspbian packaging).
Also staged (separately from the build scripts above):
- src/test/fuzz/transaction_deserialize_fuzz.cpp: libFuzzer harness for
CTransaction deserialization. Reads raw attacker-controlled bytes
into a CDataStream and calls Unserialize on a CTransaction, then
exercises hash determinism, round-trip serialize/parse, and
CheckTransaction bounds. Mirrors the Bitcoin Core deserialize-fuzz
pattern. Not yet wired into src/CMakeLists.txt — the BUILD_FUZZ=ON
gate currently only builds fuzz_script; a follow-up patch should add
the analogous stanza for this target.
The script previously assumed libtor.a and libi2pd*.a were already
present, but on a fresh checkout they only exist after running
src/tor/build-libtor.sh and src/i2p/build-libi2pd.sh. CI does this
in build-all.yml but local verification didn't, which bit me during
the v6.1.5 release.
Detect missing static libs and invoke the build scripts (passing
/usr paths for native Linux, matching what CI does). On a fresh
checkout this adds ~8 min to first-run verification; subsequent
runs skip the build step.
Logs go to /tmp/triangles-build-lib{tor,i2pd}.log for debugging.
Exit code 5 distinguishes build-prep failures from cmake/build
failures (3) and binary-compare failures (1/4).
Adds the infrastructure for verifiable Triangles releases:
- Reproducible builds (default-on): -ffile-prefix-map strips absolute
source paths from binaries; SOURCE_DATE_EPOCH pinned to commit
timestamp if env var not set. Two builds of the same commit with the
same flags now produce byte-identical binaries.
- scripts/verify-reproducible-build.sh: builds the daemon twice into
separate build dirs and compares SHA256. Pass/fail printed clearly.
- scripts/sign-release.sh: generates SHA256SUMS, writes detached .asc
signatures over each release artifact and over SHA256SUMS itself.
Supports --verify for independent third-party verification.
- release-process.md: canonical release pipeline documentation --
reproducibility properties, signing-key setup, distribution
requirements, failure-mode recovery, and the release checklist.
- scripts/README.md: updated to catalog the full scripts/ directory
(was previously scoped only to bump-version.sh).
Verified end-to-end on this branch:
- scripts/verify-reproducible-build.sh: exit 0, both builds SHA256
7a86d9659b7150f69dc53eb31cc4c7eb8df296b55fa889af5c5a1b310223c894.
- scripts/sign-release.sh: signs Release-built artifact, --verify
returns exit 0 (all sigs + checksums valid).
- ctest: 4/4 suites still pass with the new compile flags.
- Tamper test: modifying an artifact after signing causes --verify
to fail with '1 checksum(s) FAILED' (exit 1).
Existing signing key in the local keyring is used:
523A81833EB7201573E1EFE1DCF2579968107984
(Krystie Triangles Release <krystie-triangles-release@dns2.sami.tailnet>)
CI integration (separate PR): add a 'sign' job to build-all.yml that
imports GPG_PRIVATE_KEY from secrets and runs scripts/sign-release.sh
against the assembled release directory. Documented in release-process.md.
The macOS build of e2cd0b6 (the NeedsBootstrap rocksdb/ fix) failed at
the 'Bundle Tor into app' step with bash exit code 6 after exactly 30s
of curl hanging against archive.torproject.org. All 4 Tor download
sites (Windows Qt, Windows daemon, Linux Qt .deb, Linux daemon .deb,
macOS Qt) used 'curl -sL' with no timeouts and no retries — a single
transient network drop from Azure westus to the Tor archive killed
the job.
Fix at all 4 sites:
* curl -fSL (HTTP error -> non-zero exit; fail loudly)
* --connect-timeout 15 / --max-time 120 (per-attempt bounds)
* --retry 3 --retry-delay 5 --retry-connrefused --retry-all-errors
(covers 5xx, DNS timeouts, and connection refused)
* 'set -euo pipefail' at script top so any failure aborts cleanly
* PowerShell variants get a manual retry loop with size check
(1MB minimum — a 0-byte '200 OK' response from a broken mirror
used to silently slip through)
Also bump CLIENT_VERSION_REVISION 1 -> 4 (v6.1.4) for the upcoming
release that will include e2cd0b6 (NeedsBootstrap rocksdb/ fix).
Release notes:
v6.1.4: Tor bundle download resilience (4 CI sites hardened)
+ e2cd0b6 (NeedsBootstrap rocksdb/ chain state detection). Supersedes
v6.1.3 only on CI reliability; no protocol/wallet/chain format changes.
RocksDB's install-shared writes a rocksdb.pc with both:
-isystem third-party/gtest-1.8.1/fused-src
-std=c++17
The previous PR fix scrubbed the bad include path but left -std=c++17.
pkg-config consumers inherit that flag via INTERFACE_COMPILE_OPTIONS,
which propagates to CMake imported targets as a compile option.
Result: Triangles' configure sets CXX_STANDARD 20, but the compile
command line ends up with '-std=c++20 ... -std=c++17' (rocksdb.pc's
flag comes last and wins). GCC reports:
error: defaulted 'bool operator!=...' only available with
'-std=c++20' or '-std=gnu++20'
Strip -std=c++17 from Cflags. Triangles sets its own standard via
CMake; the flag from rocksdb.pc was never useful anyway (consumers
should choose their own standard).
This bug only surfaced now because we replaced librocksdb-dev 6.11.4
with a locally-built RocksDB 8.9.1 — the system package's .pc didn't
have this -std flag, the freshly-built one does.
The previous sed expression had \${prefix} in a double-quoted string,
which bash was expanding to a literal prefix variable lookup. With
`set -euo pipefail` and unbound variables causing exit, the entire
script aborted right after `make install-shared`, before ldconfig
and the sanity check ran.
Use single quotes around the sed expression so bash leaves the
\${prefix} alone for sed to interpret.
Discovered via:
scripts/ci/build-rocksdb.sh: line 57: prefix: unbound variable
RocksDB's Makefile unconditionally appends `-isystem third-party/
gtest-1.8.1/fused-src` to the generated rocksdb.pc Cflags. That path
is relative to the build directory, so when the installed .pc file
ends up in /usr/local/lib/pkgconfig/, Triangles' CMake configure
errors out with:
CMake Error in src/CMakeLists.txt:
Imported target 'PkgConfig::RocksDB' includes non-existent path
'third-party/gtest-1.8.1/fused-src'
Modern CMake (>= 3.27) refuses imported targets with relative paths
in INTERFACE_INCLUDE_DIRECTORIES. Replace the bad flag with an
absolute path to the installed include dir so pkg-config consumers
get a real on-disk path.
Discovered while debugging the second CI failure on PR #10
(Configure succeeded but generation failed because PkgConfig::RocksDB
referenced a path that didn't exist).
The previous sanity check matched against `librocksdb.so.${ROCKSDB_VERSION}`
(full semver like 8.9.1), but `ldconfig -p` only prints major.minor
(e.g. `librocksdb.so.8.9`). The library was correctly installed but
the check failed, killing the CI job before Configure could run.
Check the versioned file on disk first (definitive), then ldconfig with
the major.minor pattern (sanity for runtime linker). Both must pass.
Discovered when investigating CI failure on PR #10.
PR #10 added a configure-time FATAL_ERROR for RocksDB < 7.4.0 because
the v5.9.24 daemon on DNS2 was built against librocksdb 6.11 and can't
read smsgDB SST files written by newer RocksDB (XXH3 per-block
checksum). The check worked — but it immediately failed CI, because
GitHub's ubuntu-22.04 runners also ship librocksdb-dev 6.11.4.
This is the same drift class the original patch was meant to prevent.
Fix: build RocksDB from source in CI, pinned to 8.9.1 (matching DNS2's
system version). Add scripts/ci/build-rocksdb.sh as a reusable helper
and call it from each of the four Linux jobs (test-linux-unit,
test-linux-sanitizers, build-linux-daemon, build-linux-qt). Drop
librocksdb-dev from the apt-get install (otherwise find_library would
pick up /usr/lib/librocksdb.so.6.11.4 first) and add libsnappy-dev /
libzstd-dev / liblz4-dev (compression libs RocksDB optionally links
against).
MacOS was already passing — Homebrew's rocksdb is current. Windows
was already passing — MSYS2's mingw-w64-rocksdb is at 9.x.
Also fix a cosmetic CMake bug: the version-detect function was setting
RocksDB_VERSION with PARENT_SCOPE only, so the 'Detected RocksDB
version from version.h:' message printed an empty value. Set the local
variable too so the STATUS message reflects the real value.
The hook scans every staged file for:
1. Filename matches: triangles.conf, *.onion
2. Content matches: lines starting with 'addnode=' followed by a
base32-encoded .onion address
If any address fails v3 onion checksum validation, the commit is blocked
with a clear diagnostic showing the bad address, the reason, and (when
possible) a suggestion of the correct address.
Run with --ci mode on the validator so it exits 1 on any failure.
Install:
cp scripts/pre-commit .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Bypass (NEVER do this for normal commits):
git commit --no-verify
Tested:
✓ Clean config: commit allowed, validator says PASSED
✓ Corrupted config (btb6 vs gtb6): commit blocked with full
diagnostic + 'did you mean: gtb6?' suggestion
Detects corrupted .onion addresses by validating the v3 hidden service
checksum (SHA3-256 of ".onion checksum" || pubkey || version).
Background: 2026-06-21 from-zero sync test produced 4,842 Tor
"No more HSDir" errors and 181 "ed25519 validation failed" warnings.
Root cause: a 1-character transposition (btb6 vs gtb6) in the test
config's vmepp seed address. This tool would have caught it in 0.1s.
Usage:
./scripts/validate_onion_seeds.py /root/.triangles/triangles.conf
./scripts/validate_onion_seeds.py /path/to/triangles.conf --ci
./scripts/validate_onion_seeds.py /path/to/triangles.conf \
--against /root/triangles_v5/src/onionseed.h
Features:
* Validates every addnode= line against v3 onion checksum
* Suggests the correct address if 1-2 char transposition detected
* Detects truncated/extended/non-base32 addresses
* Cross-checks multiple configs (catches test vs prod mismatches)
* CI mode exits 1 on any failure (gates deploys)
* Pure stdlib, no pip deps (works in any Python 3.8+ env)
A bash command interface to trianglesd RPC designed for Hermes, Krystie,
and Sami to manage TRI wallets and communicate via the built-in secure
messaging system (smessage).
Features:
- Info: status, balance, peers, staking info
- Wallet: addresses, send, transactions
- Secure messaging: inbox, outbox, send (encrypted via ECDH over Tor P2P)
- Raw RPC passthrough for any daemon command
- Bash + zsh completion
- SSH-tunneled RPC for remote node access
- Config at /etc/tri/nodes.conf (shared between agents)
Files:
- scripts/tri/tri Main script
- scripts/tri/nodes.conf.example Config template
- scripts/tri/tri-completion.bash Bash completion
- scripts/tri/_tri_zsh_completion Zsh completion
- scripts/tri/README.md Documentation
Tested against live DNS3 node (block 2,207,455, 4 peers).
Secure messaging verified: send → inbox → outbox all working.
Adds the foundation for the snapshot-based IBD:
- sign-snapshot.sh: operator-side script to sign canonical snapshots
- utxosnapshot gate requireCheckpoint on trust source
- utxosnapshot build address index when loading (wallet balance support)
- main build address index during FastImport
- build: ignore build-*/ directories
* Add triangles-cli: JSON-RPC client (port bitcoin-cli pattern)
Triangles never had a CLI client (bitcoin-cli analog). This adds
triangles-cli as a third build target alongside trianglesd and
triangles-qt.
- src/triangles-cli.cpp: self-contained JSON-RPC 1.0 client.
Reads triangles.conf for credentials, supports -rpcuser/-rpcpassword
/-rpcconnect/-rpcport/-testnet/-datadir/-conf flags. Implements
-getinfo (synthesized summary from getnetworkinfo/getblockchaininfo
/getwalletinfo) and raw method dispatch. JSON via json_spirit compat
shim (json_compat.h), HTTP via boost::asio, base64 auth inline.
No util.cpp / wallet.cpp / net.cpp / triangles_common link dep —
keeps the binary small (~600 KB Linux, ~1.5 MB Windows).
- CMake: new option(BUILD_CLI ON) + add_executable(triangles-cli)
in src/CMakeLists.txt. Status line added.
- CI: BUILD_CLI=ON added to build-windows-daemon and build-linux-daemon
jobs. triangles-cli.exe bundled into windows-daemon artifact
alongside trianglesd.exe. triangles-cli added to linux-daemon .deb
package (with launcher in /usr/bin).
- Default ON; set BUILD_CLI=OFF to skip.
Closes the open 'triangles-cli.exe missing from Windows build'
follow-up (the binary wasn't missing — it never existed).
Patterned after Bitcoin Core bitcoin-cli and Dash Core dash-cli.
* Fix macOS build: drop Boost::system/find_package component, use std::filesystem
Homebrew's boost formula doesn't ship the boost_system CMake config file,
so find_package(Boost REQUIRED COMPONENTS system) failed on macOS.
- Replace boost::filesystem with std::filesystem (C++17, no Boost dep)
- Drop 'filesystem' from find_package — only headers needed (asio + system)
- Link libboost_system explicitly per-platform by library name, resolved
via the platform's default search path (Homebrew toolchain on macOS,
system libs on Linux, MSYS2 on Windows)
CI will rerun automatically on PR push.
* Fix macOS build: add Boost::boost target for headers, link boost_system
The previous fix dropped the find_package component but also killed the
boost include path. Now use the modern Boost::boost header-only target
(available in Boost 1.83+) which sets up include directories without
requiring a per-component config file.
Link libboost_system explicitly by name on all platforms — the linker
finds it via the platform's default search path:
- Linux: /usr/lib (libboost_system.so)
- macOS Homebrew: /opt/homebrew/lib (libboost_system.dylib)
- Windows MSYS2: mingw64/bin (libboost_system-mt-X-XX.dll)
* Drop Boost entirely from triangles-cli: use raw sockets for HTTP
Third time's the charm. After two CI failures chasing boost::asio / libboost_system
linking issues across platforms (Homebrew missing config on macOS, MSYS2 versioned
names on Windows, CMake targets that don't quite work everywhere), rip the whole
Boost dependency out of the CLI and use raw POSIX/Winsock sockets.
- triangles-cli.cpp: replaced boost::asio with raw socket() / connect() / send()
/ recv() / getaddrinfo(). Cross-platform: #ifdef _WIN32 for Winsock + WSAStartup
/ WSACleanup, else POSIX. ~100 lines of clean portable socket code.
- src/CMakeLists.txt: dropped find_package(Boost) entirely. Only links
json_compat (header-only) + ws2_32 on Windows. No boost libs to find.
Should be the last fix needed for this PR.
* Fix Windows packaging step: simplify bash { } | sort -u | while pattern
The previous step used a bash group command piped through sort -u and a
while loop. Under MSYS2 bash + 'set -e -o pipefail' (GitHub Actions
default), this triggered a non-zero exit even when the loop body
succeeded, causing the Windows daemon job to fail at the packaging step
(the actual link of both trianglesd.exe and triangles-cli.exe succeeded).
Replaced the { } | sort -u | while pattern with a temp-file-based dedup:
- ldd both binaries, append to /tmp/cli-dlls.txt (or cli-libs.txt on Linux)
- sort -u the temp file
- pipe the result into the while loop (simpler pipeline, no group)
Also applied the same simplification to the Linux .deb packaging for
consistency, even though the Linux build was passing.
* Simplify DLL packaging: plain for loop, no pipe-into-while
The previous attempts used 'ldd | sort -u | while read; do ... done' patterns
that exit 1 under MSYS2 bash + 'set -e -o pipefail' even when the script
ran successfully. Replaced with a plain 'for bin in ...; do ldd > list.txt;
while read; do cp; done < list.txt; done' pattern that has no pipelines
other than the standard redirection, and uses IFS= read -r for safe line
iteration.
Also moved temp files from /tmp to the working directory (./dll-list.txt)
to avoid any MSYS2 /tmp path-translation edge cases.
* diagnostic: add tracing to Windows packaging step
* Add package-windows-daemon.sh + package-linux-daemon.sh scripts
Move the Windows daemon packaging step and the Linux .deb build into
committed shell scripts under scripts/ci/. This bypasses GitHub Actions'
inline-run-block quirks (silent exit 1 under msys2 + set -e -o pipefail
with multi-line scripts) and makes the packaging logic debuggable locally.
* Switch to script-file packaging for Windows + Linux daemon jobs
Replace inline multi-line run: blocks with invocations of the
scripts/ci/package-*.sh scripts. This sidesteps the GitHub Actions
msys2 + 'set -e -o pipefail' issue that caused silent exit 1 on the
Windows daemon packaging step. The scripts are also debuggable locally.
---------
Co-authored-by: Krystie <krystie@sami>
Generates a UTXO snapshot via dumputxoset RPC, signs a provenance message
(height, blockhash, snapshot sha256) with signmessage, and emits a signed
manifest.json. Verification via ./sign-snapshot.sh verify <manifest> <snap>
or verifymessage RPC on any node.
Pairs with the requireCheckpoint trust-gate patch — local snapshots no
longer require a known checkpoint, so signing provenance is the way to
establish authority for a snapshot.
Every Triangles wallet is now a Tor node. Staking rewards subsidize
Tor infrastructure.
Core changes:
- Embedded Tor 0.4.9.6 as git submodule
- ConnectNode rejects all non-.onion peers
- Tor failure is fatal - wallet requires Tor to operate
- All proxies forced through embedded Tor SOCKS
- Clearnet (IPv4/IPv6) disabled at startup
- HTTP seed fetch routes through Tor proxy (removed boost::asio dep)
- Merged PoW cleanup: -623 lines of dead mining code
- Stripped dead LEGACY/MIXED bootstrap modes from net_bootstrap
- RPC getnetworkinfo reports tor_native mode
Tooling:
- scripts/bump-version.sh syncs version across all 17+ files
- Version bumped to 5.6.0 across all packaging manifests
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Single command to update version across all 12+ files:
scripts/bump-version.sh 5.7.0
Updates: clientversion.h, version.h, triangles-qt.pro, Dockerfile,
and all packaging manifests (Docker, AUR, Chocolatey, Debian, RPM,
WinGet, Homebrew, Nix, AppImage).