v5.6.0 Tor-native: embed Tor, force .onion-only networking

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>
This commit is contained in:
2026-04-03 17:52:32 -07:00
parent 279d643582
commit 42a33457bf
23 changed files with 305 additions and 524 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "src/tor/tor-src"]
path = src/tor/tor-src
url = https://gitlab.torproject.org/tpo/core/tor.git
+3 -2
View File
@@ -2,7 +2,7 @@ FROM ubuntu:22.04
LABEL maintainer="Cryptographic Triangles Team"
LABEL description="Cryptographic Triangles (TRI) headless daemon"
LABEL version="5.5.5"
LABEL version="5.6.0"
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
@@ -19,8 +19,9 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
tor \
&& rm -rf /var/lib/apt/lists/*
ARG VERSION=5.6.0
RUN curl -L -o /usr/local/bin/trianglesd \
https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.1.5/trianglesd-linux \
https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}/Cryptographic-Triangles-v${VERSION}-linux-x64-daemon \
&& chmod +x /usr/local/bin/trianglesd
RUN useradd -m -s /bin/bash triangles
+1 -1
View File
@@ -3,7 +3,7 @@
# Run on a Linux x64 system with appimagetool installed
set -e
VERSION="5.5.5"
VERSION="5.6.0"
APPDIR="Triangles-x86_64.AppDir"
RELEASE_URL="https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}"
+1 -1
View File
@@ -3,7 +3,7 @@
# Run from the packaging/debian directory
set -e
VERSION="5.3.7"
VERSION="5.6.0"
PKGDIR="triangles_${VERSION}-1_amd64"
RELEASE_URL="https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}"
+2 -2
View File
@@ -2,9 +2,9 @@ FROM ubuntu:22.04
LABEL maintainer="Cryptographic Triangles Team"
LABEL description="Cryptographic Triangles (TRI) headless daemon"
LABEL version="5.5.5"
LABEL version="5.6.0"
ARG VERSION=5.3.7
ARG VERSION=5.6.0
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
+1 -1
View File
@@ -3,7 +3,7 @@ version: "3.8"
services:
trianglesd:
build: .
image: cryptographic-triangles/trianglesd:5.3.7
image: cryptographic-triangles/trianglesd:5.6.0
container_name: trianglesd
restart: unless-stopped
ports:
@@ -25,7 +25,7 @@ modules:
- install -Dm644 org.cryptographic_triangles.TrianglesQt.metainfo.xml /app/share/metainfo/org.cryptographic_triangles.TrianglesQt.metainfo.xml
sources:
- type: file
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-qt
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.6.0/Cryptographic-Triangles-v5.6.0-linux-x64-qt
sha256: ed220eb8d0b403f62cdac28988541fd1a27864491e233216f9c00a4c2537b4a3
dest-filename: triangles-qt-linux
- type: file
@@ -55,6 +55,6 @@ modules:
- install -Dm755 trianglesd-linux /app/bin/trianglesd
sources:
- type: file
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-daemon
url: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.6.0/Cryptographic-Triangles-v5.6.0-linux-x64-daemon
sha256: 4d2ab25d61127d6aff3e6f3069556d04f4b823f8849e97629c12871ad4779517
dest-filename: trianglesd-linux
+1 -1
View File
@@ -4,7 +4,7 @@
# Install build tools: sudo dnf install rpm-build rpmdevtools
set -e
VERSION="5.3.7"
VERSION="5.6.0"
RELEASE_URL="https://github.com/SamiAhmed7777/triangles_v5/releases/download/v${VERSION}"
echo "Building RPM for Triangles v${VERSION}..."
+1 -1
View File
@@ -1,5 +1,5 @@
Name: triangles
Version: 5.5.5
Version: 5.6.0
Release: 1%{?dist}
Summary: Cryptographic Triangles (TRI) cryptocurrency wallet
License: MIT
+29
View File
@@ -0,0 +1,29 @@
{
"version": "5.6.0",
"description": "Cryptographic Triangles (TRI) cryptocurrency wallet with PoS staking and encrypted messaging",
"homepage": "https://cryptographic-triangles.org",
"license": "MIT",
"architecture": {
"64bit": {
"url": "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.6.0/Cryptographic-Triangles-5.6.0-win-x64.zip",
"hash": "6f002a669a7e92aaf3d8dd7b1ae80f06a086c99a15ca05cf107665009ffc06b7"
}
},
"bin": [
"triangles-qt.exe",
"trianglesd.exe"
],
"shortcuts": [
["triangles-qt.exe", "Cryptographic Triangles"]
],
"checkver": {
"github": "https://github.com/SamiAhmed7777/triangles_v5"
},
"autoupdate": {
"architecture": {
"64bit": {
"url": "https://github.com/SamiAhmed7777/triangles_v5/releases/download/v$version/Cryptographic-Triangles-$version-win-x64.zip"
}
}
}
}
@@ -1,5 +1,5 @@
PackageIdentifier: CryptographicTriangles.TrianglesQt
PackageVersion: 5.5.5
PackageVersion: 5.6.0
PackageLocale: en-US
Publisher: Cryptographic Triangles
PublisherUrl: https://cryptographic-triangles.org
@@ -27,7 +27,7 @@ Installers:
- RelativeFilePath: triangles-qt.exe
PortableCommandAlias: triangles-qt
ArchiveBinariesDependOnPath: true
InstallerUrl: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-5.3.7-win-x64.zip
InstallerUrl: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.6.0/Cryptographic-Triangles-5.6.0-win-x64.zip
InstallerSha256: 6F002A669A7E92AAF3D8DD7B1AE80F06A086C99A15CA05CF107665009FFC06B7
ManifestType: singleton
ManifestVersion: 1.6.0
+29
View File
@@ -0,0 +1,29 @@
# Version Bump Script
Updates the version number across all files in the repo from a single command.
## Usage
**Set a specific version:**
```bash
bash scripts/bump-version.sh 5.7.0
```
**Or edit `src/clientversion.h` first, then sync everything else:**
```bash
bash scripts/bump-version.sh
```
## What it updates
- `src/clientversion.h` (source of truth)
- `src/version.h`
- `triangles-qt.pro`
- `Dockerfile`
- All packaging manifests (Docker, Snap, Scoop, WinGet, RPM, Flatpak, Debian, AppImage)
## What still needs manual review after running
- `packaging/appstream/...metainfo.xml` — add a new `<release>` entry
- `README.md` — update header version if desired
- Any documentation with download URLs
+114 -142
View File
@@ -1,177 +1,149 @@
#!/bin/bash
# bump-version.sh — Update the version number across the entire repo.
# bump-version.sh - Sync all version references from src/clientversion.h
#
# Usage:
# scripts/bump-version.sh 5.7.0 # Set version to 5.7.0
# scripts/bump-version.sh # Read from src/clientversion.h and sync everything else
# ./scripts/bump-version.sh # Read version from clientversion.h, update everything
# ./scripts/bump-version.sh 5.7.0 # Set version to 5.7.0 in clientversion.h AND everywhere else
#
# The single source of truth is src/clientversion.h
set -euo pipefail
set -e
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$REPO_ROOT"
CLIENTVERSION="$REPO_ROOT/src/clientversion.h"
# ── Parse version ──────────────────────────────────────────────
if [ -n "${1:-}" ]; then
VERSION="$1"
else
# Read from clientversion.h (source of truth)
MAJOR=$(grep '#define CLIENT_VERSION_MAJOR' src/clientversion.h | awk '{print $3}')
MINOR=$(grep '#define CLIENT_VERSION_MINOR' src/clientversion.h | awk '{print $3}')
REV=$(grep '#define CLIENT_VERSION_REVISION' src/clientversion.h | awk '{print $3}')
VERSION="${MAJOR}.${MINOR}.${REV}"
fi
# Split into components
IFS='.' read -r MAJOR MINOR REV <<< "$VERSION"
BUILD=0
if [ -z "$MAJOR" ] || [ -z "$MINOR" ] || [ -z "$REV" ]; then
echo "Error: Invalid version '$VERSION'. Expected format: X.Y.Z"
if [ ! -f "$CLIENTVERSION" ]; then
echo "ERROR: Cannot find $CLIENTVERSION"
exit 1
fi
echo "Bumping to v${VERSION} (${MAJOR}.${MINOR}.${REV}.${BUILD})"
echo ""
# If a version argument is provided, update clientversion.h first
if [ -n "$1" ]; then
IFS='.' read -r MAJOR MINOR REV <<< "$1"
REV="${REV:-0}"
BUILD=0
sed -i "s/#define CLIENT_VERSION_MAJOR.*/#define CLIENT_VERSION_MAJOR $MAJOR/" "$CLIENTVERSION"
sed -i "s/#define CLIENT_VERSION_MINOR.*/#define CLIENT_VERSION_MINOR $MINOR/" "$CLIENTVERSION"
sed -i "s/#define CLIENT_VERSION_REVISION.*/#define CLIENT_VERSION_REVISION $REV/" "$CLIENTVERSION"
sed -i "s/#define CLIENT_VERSION_BUILD.*/#define CLIENT_VERSION_BUILD $BUILD/" "$CLIENTVERSION"
echo "Updated clientversion.h to $MAJOR.$MINOR.$REV.$BUILD"
fi
# ── Helper ─────────────────────────────────────────────────────
# Read version from clientversion.h (the source of truth)
MAJOR=$(grep '#define CLIENT_VERSION_MAJOR' "$CLIENTVERSION" | awk '{print $3}')
MINOR=$(grep '#define CLIENT_VERSION_MINOR' "$CLIENTVERSION" | awk '{print $3}')
REV=$(grep '#define CLIENT_VERSION_REVISION' "$CLIENTVERSION" | awk '{print $3}')
BUILD=$(grep '#define CLIENT_VERSION_BUILD' "$CLIENTVERSION" | awk '{print $3}')
updated=()
VERSION="$MAJOR.$MINOR.$REV"
VERSION_FULL="$MAJOR.$MINOR.$REV.$BUILD"
echo "Syncing all files to version $VERSION (full: $VERSION_FULL)"
echo "==========================================================="
update_file() {
local file="$1"
local pattern="$2"
local replacement="$3"
if [ ! -f "$file" ]; then
echo " SKIP $file (not found)"
return
fi
if grep -qE "$pattern" "$file"; then
sed -i -E "s|${pattern}|${replacement}|g" "$file"
echo " OK $file"
updated+=("$file")
else
echo " SKIP $file (pattern not found)"
if [ -f "$file" ]; then
sed -i "$pattern" "$file"
echo " Updated: $file"
fi
}
# ── src/clientversion.h (source of truth) ──────────────────────
# --- Source files ---
echo "Core:"
cat > src/clientversion.h << EOF
#ifndef CLIENTVERSION_H
#define CLIENTVERSION_H
# src/version.h - DISPLAY_VERSION macros
update_file "$REPO_ROOT/src/version.h" \
"s/#define DISPLAY_VERSION_MAJOR.*/#define DISPLAY_VERSION_MAJOR $MAJOR/" ""
update_file "$REPO_ROOT/src/version.h" \
"s/#define DISPLAY_VERSION_MINOR.*/#define DISPLAY_VERSION_MINOR $MINOR/" ""
update_file "$REPO_ROOT/src/version.h" \
"s/#define DISPLAY_VERSION_REVISION.*/#define DISPLAY_VERSION_REVISION $REV/" ""
update_file "$REPO_ROOT/src/version.h" \
"s/#define DISPLAY_VERSION_BUILD.*/#define DISPLAY_VERSION_BUILD $BUILD/" ""
//
// client versioning
//
# triangles-qt.pro
update_file "$REPO_ROOT/triangles-qt.pro" \
"s/^VERSION = .*/VERSION = $VERSION_FULL/" ""
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR ${MAJOR}
#define CLIENT_VERSION_MINOR ${MINOR}
#define CLIENT_VERSION_REVISION ${REV}
#define CLIENT_VERSION_BUILD ${BUILD}
# --- Docker ---
// Converts the parameter X to a string after macro replacement on X has been performed.
// Don't merge these into one macro!
#define STRINGIZE(X) DO_STRINGIZE(X)
#define DO_STRINGIZE(X) #X
update_file "$REPO_ROOT/Dockerfile" \
"s/LABEL version=\"[^\"]*\"/LABEL version=\"$VERSION\"/" ""
#endif // CLIENTVERSION_H
EOF
echo " OK src/clientversion.h"
updated+=("src/clientversion.h")
update_file "$REPO_ROOT/packaging/docker/Dockerfile" \
"s/LABEL version=\"[^\"]*\"/LABEL version=\"$VERSION\"/" ""
update_file "$REPO_ROOT/packaging/docker/Dockerfile" \
"s/ARG VERSION=.*/ARG VERSION=$VERSION/" ""
# ── triangles-qt.pro ───────────────────────────────────────────
update_file "$REPO_ROOT/packaging/docker/docker-compose.yml" \
"s|cryptographic-triangles/trianglesd:[0-9.]*|cryptographic-triangles/trianglesd:$VERSION|" ""
update_file "triangles-qt.pro" \
"^VERSION = [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" \
"VERSION = ${MAJOR}.${MINOR}.${REV}.${BUILD}"
# --- Snap ---
# ── Root Dockerfile ────────────────────────────────────────────
update_file "Dockerfile" \
'LABEL version="[0-9]+\.[0-9]+\.[0-9]+"' \
"LABEL version=\"${VERSION}\""
# ── Packaging manifests ────────────────────────────────────────
echo ""
echo "Packaging:"
# Docker
update_file "packaging/docker/Dockerfile" \
'LABEL version="[0-9]+\.[0-9]+\.[0-9]+"' \
"LABEL version=\"${VERSION}\""
update_file "packaging/docker/docker-compose.yml" \
'image: triangles:[0-9]+\.[0-9]+\.[0-9]+' \
"image: triangles:${VERSION}"
# AUR
update_file "packaging/aur/PKGBUILD" \
"^pkgver=[0-9]+\.[0-9]+\.[0-9]+" \
"pkgver=${VERSION}"
# Chocolatey
update_file "packaging/chocolatey/triangles.nuspec" \
"<version>[0-9]+\.[0-9]+\.[0-9]+</version>" \
"<version>${VERSION}</version>"
# Debian
update_file "packaging/debian/DEBIAN/control" \
"^Version: [0-9]+\.[0-9]+\.[0-9]+-[0-9]+" \
"Version: ${VERSION}-1"
# RPM
update_file "packaging/rpm/triangles.spec" \
"^Version:[[:space:]]+[0-9]+\.[0-9]+\.[0-9]+" \
"Version: ${VERSION}"
# WinGet
update_file "packaging/winget/CryptographicTriangles.TrianglesQt.yaml" \
"^PackageVersion: [0-9]+\.[0-9]+\.[0-9]+" \
"PackageVersion: ${VERSION}"
# Homebrew
update_file "packaging/homebrew/triangles.rb" \
'version "[0-9]+\.[0-9]+\.[0-9]+"' \
"version \"${VERSION}\""
# Nix
update_file "packaging/nix/default.nix" \
'version = "[0-9]+\.[0-9]+\.[0-9]+"' \
"version = \"${VERSION}\""
# Flatpak — only update the app version tag, not runtime-version
if [ -f "packaging/flatpak/org.cryptographic_triangles.TrianglesQt.yml" ]; then
# The flatpak manifest doesn't have a simple version field to sed,
# so we update any tag: line that has our version pattern
echo " NOTE packaging/flatpak/ — check manually for version references"
update_file "$REPO_ROOT/snap/snapcraft.yaml" \
"s/^version: '[^']*'/version: '$VERSION'/" ""
# Update download URLs in snapcraft.yaml
if [ -f "$REPO_ROOT/snap/snapcraft.yaml" ]; then
sed -i "s|/download/v[0-9.]*\/|/download/v$VERSION/|g" "$REPO_ROOT/snap/snapcraft.yaml"
sed -i "s/Cryptographic-Triangles-v[0-9.]*-linux/Cryptographic-Triangles-v$VERSION-linux/g" "$REPO_ROOT/snap/snapcraft.yaml"
fi
# AppImage build script
update_file "packaging/appimage/build-appimage.sh" \
'VERSION="[0-9]+\.[0-9]+\.[0-9]+"' \
"VERSION=\"${VERSION}\""
# --- Scoop ---
update_file "packaging/appimage/build-appimage.sh" \
"VERSION=[0-9]+\.[0-9]+\.[0-9]+" \
"VERSION=${VERSION}"
if [ -f "$REPO_ROOT/packaging/scoop/triangles.json" ]; then
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" "$REPO_ROOT/packaging/scoop/triangles.json"
sed -i "s|/download/v[0-9.]*/|/download/v$VERSION/|g" "$REPO_ROOT/packaging/scoop/triangles.json"
sed -i "s/Cryptographic-Triangles-[0-9.]*-win/Cryptographic-Triangles-$VERSION-win/g" "$REPO_ROOT/packaging/scoop/triangles.json"
echo " Updated: packaging/scoop/triangles.json"
fi
# ── Summary ────────────────────────────────────────────────────
# --- WinGet ---
if [ -f "$REPO_ROOT/packaging/winget/CryptographicTriangles.TrianglesQt.yaml" ]; then
sed -i "s/PackageVersion: .*/PackageVersion: $VERSION/" "$REPO_ROOT/packaging/winget/CryptographicTriangles.TrianglesQt.yaml"
sed -i "s|/download/v[0-9.]*/|/download/v$VERSION/|g" "$REPO_ROOT/packaging/winget/CryptographicTriangles.TrianglesQt.yaml"
sed -i "s/Cryptographic-Triangles-[0-9.]*-win/Cryptographic-Triangles-$VERSION-win/g" "$REPO_ROOT/packaging/winget/CryptographicTriangles.TrianglesQt.yaml"
echo " Updated: packaging/winget/CryptographicTriangles.TrianglesQt.yaml"
fi
# --- RPM ---
update_file "$REPO_ROOT/packaging/rpm/triangles.spec" \
"s/^Version: .*/Version: $VERSION/" ""
if [ -f "$REPO_ROOT/packaging/rpm/build-rpm.sh" ]; then
sed -i "s/^VERSION=\"[^\"]*\"/VERSION=\"$VERSION\"/" "$REPO_ROOT/packaging/rpm/build-rpm.sh"
echo " Updated: packaging/rpm/build-rpm.sh"
fi
# --- Flatpak ---
if [ -f "$REPO_ROOT/packaging/flatpak/org.cryptographic_triangles.TrianglesQt.yml" ]; then
sed -i "s|/download/v[0-9.]*/|/download/v$VERSION/|g" "$REPO_ROOT/packaging/flatpak/org.cryptographic_triangles.TrianglesQt.yml"
sed -i "s/Cryptographic-Triangles-v[0-9.]*-linux/Cryptographic-Triangles-v$VERSION-linux/g" "$REPO_ROOT/packaging/flatpak/org.cryptographic_triangles.TrianglesQt.yml"
echo " Updated: packaging/flatpak/org.cryptographic_triangles.TrianglesQt.yml"
fi
# --- Debian ---
if [ -f "$REPO_ROOT/packaging/debian/build-deb.sh" ]; then
sed -i "s/^VERSION=\"[^\"]*\"/VERSION=\"$VERSION\"/" "$REPO_ROOT/packaging/debian/build-deb.sh"
echo " Updated: packaging/debian/build-deb.sh"
fi
# --- AppImage ---
if [ -f "$REPO_ROOT/packaging/appimage/build-appimage.sh" ]; then
sed -i "s/^VERSION=\"[^\"]*\"/VERSION=\"$VERSION\"/" "$REPO_ROOT/packaging/appimage/build-appimage.sh"
echo " Updated: packaging/appimage/build-appimage.sh"
fi
echo ""
echo "Updated ${#updated[@]} files to v${VERSION}"
echo "Done! All files synced to v$VERSION"
echo ""
echo "Still needs manual review:"
echo " - packaging/appstream/...metainfo.xml add a new <release> entry"
echo " - README.md update header version if desired"
echo " - Any documentation with download URLs"
echo ""
echo "Next steps:"
echo " git add -A && git commit -m 'Bump version to v${VERSION}'"
echo " git tag -a v${VERSION} -m 'v${VERSION}'"
echo " git push origin master && git push origin v${VERSION}"
echo "Files NOT auto-updated (require manual review):"
echo " - packaging/appstream/...metainfo.xml (add new <release> entry)"
echo " - README.md (update header version)"
echo " - Documentation .md files (update download URLs if needed)"
+5 -5
View File
@@ -1,6 +1,6 @@
name: triangles
base: core22
version: '5.3.7'
version: '5.6.0'
summary: Cryptographic Triangles (TRI) cryptocurrency wallet
description: |
Privacy-focused cryptocurrency featuring Proof-of-Stake consensus,
@@ -51,10 +51,10 @@ apps:
parts:
triangles:
plugin: dump
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-qt
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.6.0/Cryptographic-Triangles-v5.6.0-linux-x64-qt
source-type: file
organize:
Cryptographic-Triangles-v5.3.7-linux-x64-qt: bin/triangles-qt
Cryptographic-Triangles-v5.6.0-linux-x64-qt: bin/triangles-qt
stage-packages:
- libqt5widgets5
- libqt5gui5
@@ -73,10 +73,10 @@ parts:
trianglesd:
plugin: dump
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.3.7/Cryptographic-Triangles-v5.3.7-linux-x64-daemon
source: https://github.com/SamiAhmed7777/triangles_v5/releases/download/v5.6.0/Cryptographic-Triangles-v5.6.0-linux-x64-daemon
source-type: file
organize:
Cryptographic-Triangles-v5.3.7-linux-x64-daemon: bin/trianglesd
Cryptographic-Triangles-v5.6.0-linux-x64-daemon: bin/trianglesd
desktop-entry:
plugin: dump
+2 -2
View File
@@ -7,8 +7,8 @@
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 5
#define CLIENT_VERSION_MINOR 5
#define CLIENT_VERSION_REVISION 5
#define CLIENT_VERSION_MINOR 6
#define CLIENT_VERSION_REVISION 0
#define CLIENT_VERSION_BUILD 0
// Converts the parameter X to a string after macro replacement on X has been performed.
+27 -6
View File
@@ -6,6 +6,7 @@
#include "walletdb.h"
#include "trianglesrpc.h"
#include "net.h"
#include "netbase.h"
#include "init.h"
#include "util.h"
#include "ui_interface.h"
@@ -357,7 +358,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 startup and .onion connectivity") + "\n" +
" -notor " + _("Disable Tor (WARNING: wallet will not start - Tor is required)") + "\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" +
@@ -744,9 +745,9 @@ bool AppInit2()
//if (nSocksVersion != 4 && nSocksVersion != 5)
// return InitError(strprintf(_("Unknown -socks proxy version requested: %i"), nSocksVersion));
// Network selection: enable all networks (IPv4, IPv6, Tor)
// Tor is always enabled; clearnet is also allowed for seed node discovery
// Users can restrict to Tor-only with -onlynet=tor
// Network selection: Tor-native mode
// All traffic routes through embedded Tor. Clearnet (IPv4/IPv6) is disabled
// after Tor starts successfully. Only .onion peers are accepted.
if (mapArgs.count("-onlynet")) {
std::set<enum Network> nets;
for (std::string snet : mapMultiArgs["-onlynet"]) {
@@ -1146,9 +1147,29 @@ bool AppInit2()
if (torStarted) {
printf("Tor process running, SOCKS proxy at %s\n",
CTorEmbedded::GetInstance()->GetSocksProxy().c_str());
// TOR-NATIVE MODE: Force all traffic through embedded Tor
int socksPort = CTorEmbedded::GetInstance()->GetSocksPort();
CService torProxyAddr("127.0.0.1", socksPort);
SetProxy(NET_IPV4, torProxyAddr, 5);
SetProxy(NET_IPV6, torProxyAddr, 5);
SetProxy(NET_TOR, torProxyAddr, 5);
SetNameProxy(torProxyAddr, 5);
// Disable clearnet reachability - ONION ONLY
SetReachable(NET_IPV4, false);
SetReachable(NET_IPV6, false);
SetReachable(NET_TOR, true);
printf("TOR-NATIVE MODE: All network traffic forced through Tor\n");
printf(" Clearnet disabled - .onion addresses only\n");
#ifdef USE_UPNP
fUseUPnP = false;
#endif
} else {
printf("WARNING: Tor not available. .onion peers will not be reachable.\n");
printf(" Clearnet connections will still work normally.\n");
return InitError(_("Tor failed to start. Triangles requires Tor to operate."));
}
// Initialize Tor V3 identity (Ed25519 keys, onion address)
+50 -43
View File
@@ -13,7 +13,6 @@
#include "ui_interface.h"
#include "onionseed.h"
#include <boost/asio.hpp>
#include <sstream>
#ifdef WIN32
@@ -490,6 +489,14 @@ CNode* FindNode(const CService& addr)
CNode* ConnectNode(CAddress addrConnect, const char *pszDest)
{
// TOR-NATIVE: Reject all non-.onion addresses
std::string addrStr = pszDest ? std::string(pszDest) : addrConnect.ToStringIP();
if (addrStr.find(".onion") == std::string::npos) {
if (fDebug)
printf("ConnectNode(): REJECTED non-onion address: %s (Tor-native mode)\n", addrStr.c_str());
return NULL;
}
if (pszDest == NULL) {
if (IsLocal(addrConnect))
return NULL;
@@ -1449,70 +1456,70 @@ void ThreadHTTPSeedFetch2(void* parg)
seedHost = seedHost.substr(0, slashPos);
}
printf("Fetching seed list from http://%s%s ...\n", seedHost.c_str(), seedPath.c_str());
printf("Fetching seed list from http://%s%s (via Tor)...\n", seedHost.c_str(), seedPath.c_str());
try {
boost::asio::io_context io_context;
boost::asio::ip::tcp::resolver resolver(io_context);
// Connect through Tor SOCKS proxy using existing proxy-aware socket infrastructure
SOCKET hSocket = INVALID_SOCKET;
CService addrResolved;
std::string connectDest = seedHost + ":" + std::to_string(HTTP_PORT);
boost::system::error_code resolve_ec;
auto endpoints = resolver.resolve(seedHost, std::to_string(HTTP_PORT), resolve_ec);
if (resolve_ec) {
printf("HTTP seed fetch: cannot resolve %s (%s)\n", seedHost.c_str(), resolve_ec.message().c_str());
if (!ConnectSocketByName(addrResolved, hSocket, connectDest.c_str(), HTTP_PORT, nConnectTimeout)) {
printf("HTTP seed fetch: cannot connect to %s through Tor proxy\n", seedHost.c_str());
return;
}
boost::asio::ip::tcp::socket socket(io_context);
boost::asio::connect(socket, endpoints);
// Send HTTP request
std::string request =
"GET " + seedPath + " HTTP/1.1\r\n"
"Host: " + seedHost + "\r\n"
"Connection: close\r\n"
"User-Agent: Triangles\r\n"
"\r\n";
boost::asio::write(socket, boost::asio::buffer(request));
int nSent = 0;
int nLen = request.size();
while (nSent < nLen) {
int nBytes = send(hSocket, request.c_str() + nSent, nLen - nSent, 0);
if (nBytes <= 0) {
printf("HTTP seed fetch: send failed\n");
closesocket(hSocket);
return;
}
nSent += nBytes;
}
// Read response
boost::asio::streambuf response_buf;
boost::asio::read_until(socket, response_buf, "\r\n\r\n");
std::string response;
char buf[4096];
while (true) {
int nBytes = recv(hSocket, buf, sizeof(buf), 0);
if (nBytes <= 0)
break;
response.append(buf, nBytes);
}
closesocket(hSocket);
std::istream response_stream(&response_buf);
std::string http_version;
unsigned int status_code = 0;
response_stream >> http_version >> status_code;
std::string status_message;
std::getline(response_stream, status_message);
if (status_code != 200) {
printf("HTTP seed fetch: got status %u from %s\n", status_code, seedHost.c_str());
if (response.empty()) {
printf("HTTP seed fetch: empty response from %s\n", seedHost.c_str());
return;
}
// Skip remaining headers
std::string header_line;
while (std::getline(response_stream, header_line) && header_line != "\r") {}
// Read body (remainder in buffer + rest from socket)
std::string body;
// First, grab anything already buffered past the headers
if (response_buf.size() > 0) {
std::istream body_stream(&response_buf);
std::ostringstream oss;
oss << body_stream.rdbuf();
body = oss.str();
// Parse HTTP response - find end of headers
size_t headerEnd = response.find("\r\n\r\n");
if (headerEnd == std::string::npos) {
printf("HTTP seed fetch: malformed response (no header terminator)\n");
return;
}
// Read rest until EOF
boost::system::error_code ec;
while (boost::asio::read(socket, response_buf, boost::asio::transfer_at_least(1), ec)) {
std::istream s(&response_buf);
std::ostringstream oss;
oss << s.rdbuf();
body += oss.str();
// Check status code
if (response.substr(0, 12).find("200") == std::string::npos) {
printf("HTTP seed fetch: non-200 response from %s\n", seedHost.c_str());
return;
}
std::string body = response.substr(headerEnd + 4);
// Parse one address per line: "address:port" or just "address"
int found = 0;
std::istringstream lines(body);
+11 -223
View File
@@ -1,256 +1,44 @@
// Copyright (c) 2024 Triangles developers
// Network Bootstrap Implementation for Triangles v5.0.0.0
// Network Bootstrap Implementation for Triangles
// Distributed under the MIT/X11 software license
#include "net_bootstrap.h"
#include "net.h"
#include "util.h"
#include "init.h"
#include "tor/onion_v3.h"
namespace NetBootstrap {
// Forward declarations
bool InitializeLegacyBootstrap();
bool InitializeMixedBootstrap();
bool InitializeTorOnlyBootstrap();
// Global variable for tracking network activity
int64_t nTimeBestReceived = 0;
BootstrapMode GetBootstrapMode() {
// Determine bootstrap mode based on configuration
bool torEnabled = GetBoolArg("-tor", false) || GetBoolArg("-proxy", false);
bool onlyTor = GetBoolArg("-onlynet", false) && GetArg("-onlynet", "") == "tor";
if (onlyTor) {
printf("Network Bootstrap: Tor-only mode selected\n");
return BOOTSTRAP_TOR_ONLY;
} else if (torEnabled) {
printf("Network Bootstrap: Mixed Tor + clearnet mode selected\n");
return BOOTSTRAP_TOR_MIXED;
} else {
printf("Network Bootstrap: Legacy clearnet mode selected\n");
return BOOTSTRAP_LEGACY;
}
}
bool InitializeNetworkBootstrap(BootstrapMode mode) {
printf("Initializing network bootstrap (mode: %d)...\n", mode);
try {
switch (mode) {
case BOOTSTRAP_LEGACY:
return InitializeLegacyBootstrap();
case BOOTSTRAP_TOR_MIXED:
return InitializeMixedBootstrap();
case BOOTSTRAP_TOR_ONLY:
return InitializeTorOnlyBootstrap();
default:
printf("ERROR: Unknown bootstrap mode: %d\n", mode);
return false;
}
} catch (const std::exception& e) {
printf("ERROR: Exception in network bootstrap: %s\n", e.what());
return false;
}
}
bool InitializeLegacyBootstrap() {
printf("Initializing legacy network bootstrap for old wallet compatibility...\n");
// Use DNS seeds and hardcoded IP addresses
// This ensures old wallets can still connect
// Add DNS seed nodes
for (int i = 0; strDNSSeed[i] != NULL; i++) {
printf("Adding DNS seed: %s\n", strDNSSeed[i]);
// DNS resolution will be handled by the existing network code
}
// Add hardcoded IP seed nodes
for (int i = 0; i < ARRAYLEN(pnSeed); i++) {
if (pnSeed[i] != 0) {
printf("Adding IP seed: 0x%08x\n", pnSeed[i]);
// IP seeds will be processed by existing network code
}
}
printf("Legacy bootstrap initialized successfully\n");
return true;
}
bool InitializeMixedBootstrap() {
printf("Initializing mixed Tor + clearnet bootstrap...\n");
// Initialize legacy bootstrap first
if (!InitializeLegacyBootstrap()) {
printf("ERROR: Failed to initialize legacy bootstrap\n");
return false;
}
// Initialize Tor v3 functionality
if (!InitTorV3()) {
printf("WARNING: Failed to initialize Tor v3, continuing with clearnet only\n");
return true; // Don't fail completely, just continue without Tor
}
// Get Tor manager instance
CTorV3Manager* torManager = CTorV3Manager::GetInstance();
if (!torManager) {
printf("WARNING: Could not get Tor manager instance\n");
return true;
}
// Connect to Tor seed nodes
std::vector<std::string> torSeeds = torManager->GetKnownSeederNodes();
printf("Found %d Tor seed nodes\n", (int)torSeeds.size());
for (const std::string& seed : torSeeds) {
printf("Attempting to connect to Tor seed: %s\n", seed.c_str());
torManager->ConnectToSeederNode(seed);
}
printf("Mixed bootstrap initialized successfully\n");
return true;
}
bool InitializeTorOnlyBootstrap() {
printf("Initializing Tor-only bootstrap...\n");
// Initialize Tor v3 functionality
if (!InitTorV3()) {
printf("ERROR: Failed to initialize Tor v3 for Tor-only mode\n");
return false;
}
// Get Tor manager instance
CTorV3Manager* torManager = CTorV3Manager::GetInstance();
if (!torManager) {
printf("ERROR: Could not get Tor manager instance for Tor-only mode\n");
return false;
}
// Enable Tor
torManager->SetTorEnabled(true);
// Create hidden service if configured
if (GetBoolArg("-torhiddenservice", false)) {
int hiddenServicePort = GetArg("-torhiddenserviceport", NetworkConfig::TOR_HIDDEN_SERVICE_PORT);
if (!torManager->CreateWalletHiddenService(hiddenServicePort)) {
printf("WARNING: Failed to create hidden service\n");
} else {
printf("Created hidden service on port %d\n", hiddenServicePort);
// Register as seeder if enabled
if (GetBoolArg("-torseeder", false)) {
std::string onionAddress = torManager->GetWalletOnionAddress();
if (!onionAddress.empty()) {
torManager->RegisterAsSeederNode(onionAddress, hiddenServicePort);
printf("Registered as Tor seeder: %s:%d\n", onionAddress.c_str(), hiddenServicePort);
}
}
}
}
// Connect to Tor seed nodes
std::vector<std::string> torSeeds = torManager->GetKnownSeederNodes();
printf("Found %d Tor seed nodes for Tor-only mode\n", (int)torSeeds.size());
if (torSeeds.empty()) {
printf("WARNING: No Tor seed nodes available for Tor-only mode\n");
return false;
}
int connected = 0;
for (const std::string& seed : torSeeds) {
printf("Attempting to connect to Tor seed: %s\n", seed.c_str());
if (torManager->ConnectToSeederNode(seed)) {
connected++;
}
}
if (connected == 0) {
printf("ERROR: Failed to connect to any Tor seed nodes\n");
return false;
}
printf("Tor-only bootstrap initialized successfully (%d connections)\n", connected);
return true;
}
bool IsOldWalletCompatible(int protocolVersion) {
return protocolVersion >= NetworkConfig::MIN_PROTOCOL_VERSION_OLD_WALLET;
}
std::vector<std::string> GetCompatibleSeedNodes(int protocolVersion) {
std::vector<std::string> seeds;
if (protocolVersion >= NetworkConfig::CURRENT_PROTOCOL_VERSION) {
// Modern wallet - can use all seed types
// Add Tor v3 seeds
CTorV3Manager* torManager = CTorV3Manager::GetInstance();
if (torManager) {
std::vector<std::string> torSeeds = torManager->GetKnownSeederNodes();
seeds.insert(seeds.end(), torSeeds.begin(), torSeeds.end());
}
// Add DNS seeds
for (int i = 0; strDNSSeed[i] != NULL; i++) {
seeds.push_back(std::string(strDNSSeed[i]));
}
} else if (IsOldWalletCompatible(protocolVersion)) {
// Old but compatible wallet - use DNS seeds only
for (int i = 0; strDNSSeed[i] != NULL; i++) {
seeds.push_back(std::string(strDNSSeed[i]));
}
}
return seeds;
}
NetworkHealth GetNetworkHealth() {
NetworkHealth health;
health.connectedPeers = 0;
health.torPeers = 0;
health.clearnetPeers = 0;
health.isBootstrapped = false;
health.isSyncing = false;
health.lastBlockTime = 0;
// Count connected peers
{
LOCK(cs_vNodes);
health.connectedPeers = vNodes.size();
// Count Tor vs clearnet peers
for (CNode* pnode : vNodes) {
std::string addr = pnode->addr.ToString();
if (addr.find(".onion") != std::string::npos) {
health.torPeers++;
} else {
health.clearnetPeers++;
}
}
}
// Check if we're bootstrapped (have at least 3 connections)
// Bootstrapped if at least 3 connections
health.isBootstrapped = (health.connectedPeers >= 3);
// Check sync status
extern int nBestHeight;
// Sync status
extern int64_t nTimeBestReceived;
health.isSyncing = (nTimeBestReceived > 0 &&
GetTime() - nTimeBestReceived < 3600); // Synced within last hour
health.isSyncing = (nTimeBestReceived > 0 &&
GetTime() - nTimeBestReceived < 3600);
health.lastBlockTime = nTimeBestReceived;
return health;
}
} // namespace NetBootstrap
} // namespace NetBootstrap
+16 -53
View File
@@ -1,5 +1,5 @@
// Copyright (c) 2024 Triangles developers
// Network Bootstrap Configuration for Triangles v5.0.0.0
// Network Bootstrap Configuration for Triangles
// Distributed under the MIT/X11 software license
#ifndef TRIANGLES_NET_BOOTSTRAP_H
@@ -9,82 +9,45 @@
#include <string>
#include <vector>
// Network bootstrap configuration for preserving old wallets
// while enabling modern Tor v3 functionality
// Tor-native network bootstrap configuration.
// All connections route through embedded Tor. Clearnet is disabled.
namespace NetBootstrap {
// DNS seed nodes for initial bootstrap (clearnet fallback)
// Unused attribute prevents warnings
static const char* strDNSSeed[] __attribute__((unused)) = {
"seed1.cryptographic-triangles.org",
"seed2.cryptographic-triangles.org",
"seed3.cryptographic-triangles.org",
"backup-seed.cryptographic-triangles.org",
NULL
};
// Hardcoded seeds removed - peer discovery is now fully dynamic via HTTP seed list.
// See: seeds.cryptographic-triangles.org
static const unsigned int pnSeed[] __attribute__((unused)) = {
};
// Network protocol compatibility settings
struct NetworkConfig {
// Preserve compatibility with old wallets
static const int MIN_PROTOCOL_VERSION_OLD_WALLET = 70200;
static const int CURRENT_PROTOCOL_VERSION = 70205;
// Network ports (preserved from existing configuration)
// Network ports
static const int DEFAULT_PORT_MAINNET = 24112;
static const int DEFAULT_PORT_TESTNET = 24111;
static const int DEFAULT_RPC_PORT_MAINNET = 19112;
static const int DEFAULT_RPC_PORT_TESTNET = 19111;
// Connection limits for different node types
static const int MAX_CONNECTIONS_DEFAULT = 125;
static const int MAX_CONNECTIONS_TOR_ONLY = 64;
// Connection limits
static const int MAX_CONNECTIONS_DEFAULT = 64;
static const int MAX_OUTBOUND_CONNECTIONS = 8;
// Tor-specific configuration
// Tor configuration
static const int TOR_HIDDEN_SERVICE_PORT = 24112;
static constexpr const char* TOR_PROXY_DEFAULT = "127.0.0.1:9050";
// Network timeouts and retry settings
// Timeouts
static const int CONNECTION_TIMEOUT_SECONDS = 30;
static const int PEER_DISCOVERY_INTERVAL_SECONDS = 3600; // 1 hour
static const int SEEDER_ANNOUNCEMENT_INTERVAL_SECONDS = 1800; // 30 minutes
static const int PEER_DISCOVERY_INTERVAL_SECONDS = 3600;
};
// Bootstrap sequence for different wallet types
enum BootstrapMode {
BOOTSTRAP_LEGACY, // Old wallets without Tor
BOOTSTRAP_TOR_MIXED, // Mixed clearnet + Tor
BOOTSTRAP_TOR_ONLY // Tor-only mode
};
// Get bootstrap configuration based on wallet capabilities
BootstrapMode GetBootstrapMode();
// Initialize network bootstrap based on configuration
bool InitializeNetworkBootstrap(BootstrapMode mode);
// Backward compatibility helpers
bool IsOldWalletCompatible(int protocolVersion);
std::vector<std::string> GetCompatibleSeedNodes(int protocolVersion);
// Network health monitoring
struct NetworkHealth {
int connectedPeers;
int torPeers;
int clearnetPeers;
bool isBootstrapped;
bool isSyncing;
int64_t lastBlockTime;
};
NetworkHealth GetNetworkHealth();
} // namespace NetBootstrap
#endif // TRIANGLES_NET_BOOTSTRAP_H
#endif // TRIANGLES_NET_BOOTSTRAP_H
+1 -33
View File
@@ -14,37 +14,6 @@
using namespace json_spirit;
using namespace std;
namespace {
const char* BootstrapModeToString(NetBootstrap::BootstrapMode mode)
{
switch (mode)
{
case NetBootstrap::BOOTSTRAP_LEGACY:
return "legacy";
case NetBootstrap::BOOTSTRAP_TOR_MIXED:
return "tor_mixed";
case NetBootstrap::BOOTSTRAP_TOR_ONLY:
return "tor_only";
}
return "unknown";
}
NetBootstrap::BootstrapMode GetBootstrapModeForRPC()
{
const bool torEnabled = GetBoolArg("-tor", false) || GetBoolArg("-proxy", false);
const bool onlyTor = GetBoolArg("-onlynet", false) && GetArg("-onlynet", "") == "tor";
if (onlyTor)
return NetBootstrap::BOOTSTRAP_TOR_ONLY;
if (torEnabled)
return NetBootstrap::BOOTSTRAP_TOR_MIXED;
return NetBootstrap::BOOTSTRAP_LEGACY;
}
} // namespace
Value getnetworkinfo(const Array& params, bool fHelp)
{
if (fHelp || params.size() != 0)
@@ -60,11 +29,10 @@ Value getnetworkinfo(const Array& params, bool fHelp)
Object healthObj;
healthObj.push_back(Pair("connectedpeers", health.connectedPeers));
healthObj.push_back(Pair("torpeers", health.torPeers));
healthObj.push_back(Pair("clearnetpeers", health.clearnetPeers));
healthObj.push_back(Pair("bootstrapped", health.isBootstrapped));
healthObj.push_back(Pair("syncing", health.isSyncing));
healthObj.push_back(Pair("lastblocktime", static_cast<boost::int64_t>(health.lastBlockTime)));
healthObj.push_back(Pair("bootstrapmode", BootstrapModeToString(GetBootstrapModeForRPC())));
healthObj.push_back(Pair("networkmode", "tor_native"));
Object obj;
obj.push_back(Pair("version", FormatFullVersion()));
+2 -2
View File
@@ -52,8 +52,8 @@ static const int BIP0031_VERSION = 60000;
static const int MEMPOOL_GD_VERSION = 60002;
#define DISPLAY_VERSION_MAJOR 5
#define DISPLAY_VERSION_MINOR 3
#define DISPLAY_VERSION_REVISION 8
#define DISPLAY_VERSION_MINOR 6
#define DISPLAY_VERSION_REVISION 0
#define DISPLAY_VERSION_BUILD 0
#endif
+1 -1
View File
@@ -1,7 +1,7 @@
TEMPLATE = app
TARGET = triangles-qt
VERSION = 5.5.5.0
VERSION = 5.6.0.0
INCLUDEPATH += src src/json src/qt src/qt/plugins/mrichtexteditor
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN BOOST_BIND_GLOBAL_PLACEHOLDERS __NO_SYSTEM_INCLUDES
CONFIG += no_include_pwd