- Replace random_shuffle (removed in C++17) with std::shuffle in wallet.cpp - Add -std=c++17 to makefile.mingw (Windows daemon was missing it) - Add lz4.o, tor_embed_hooks.o, tor_embedded.o to makefile.mingw OBJS - Add build rules for new objects in makefile.mingw - Simplify Tor embedded build to use aggregate libtor.a Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.7 KiB
Embedded Tor Integration Guide for Triangles
This guide explains how to compile Tor as a static library (libtor.a) and link
it directly into the Triangles wallet binary so that every node automatically
runs a Tor hidden service without needing an external Tor installation.
Architecture Overview
trianglesd / triangles-qt
├── tor_embedded.cpp ← calls tor_run_main() in a background thread
├── tor_process.cpp ← fallback: launches external tor binary (already works)
├── onion_v3.cpp ← V3 onion address generation / SOCKS5 proxy logic
└── libtor.a ← aggregate static Tor library (built from official source)
When compiled with ENABLE_TOR_EMBEDDED, the wallet calls tor_run_main() from
tor_api.h on a dedicated thread. This gives the wallet a SOCKS5 proxy on
127.0.0.1:19099 and a V3 hidden service on port 24112 (the P2P port).
When compiled without the flag, tor_embedded.cpp falls back to the external
tor_process.cpp which searches for and launches a system tor binary.
Step 1: Add Tor as a Git Submodule
cd /path/to/triangles
git submodule add https://gitlab.torproject.org/tpo/core/tor.git src/tor/tor-src
cd src/tor/tor-src
git checkout release-0.4.9 # latest stable branch as of 2026
This puts the full Tor source at src/tor/tor-src/.
Current imported checkout in this repo: release-0.4.9 at commit 1442ca4.
There is also a helper build script at src/tor/build-libtor.sh.
Step 2: Build libtor.a
Tor uses autotools. Build it as a static library:
cd src/tor/tor-src
# Install Tor build dependencies
sudo apt install autoconf automake libtool pkg-config \
libssl-dev libevent-dev zlib1g-dev
# Generate configure script
./autogen.sh
# Configure for static library build (disable unneeded modules)
./configure \
--enable-static-tor \
--disable-module-relay \
--disable-module-dirauth \
--disable-asciidoc \
--disable-manpage \
--disable-html-manual \
--disable-unittests \
--disable-tool-name-check \
--with-openssl-dir=/usr \
--with-libevent-dir=/usr \
--with-zlib-dir=/usr \
--prefix=/usr/local
make -j$(nproc)
Or from the repo root:
./src/tor/build-libtor.sh
After building, the static libraries are in src/tor/tor-src/:
libtor.asrc/lib/libtor-*.a(multiple component libs)
The header src/feature/api/tor_api.h provides the public C API:
tor_main_configuration_t *tor_main_configuration_new(void);
int tor_main_configuration_set_command_line(tor_main_configuration_t *cfg,
int argc, char *argv[]);
int tor_run_main(const tor_main_configuration_t *);
void tor_main_configuration_free(tor_main_configuration_t *);
Step 3: Build Triangles with Embedded Tor
Linux (makefile.unix)
cd src
# Point to Tor's built libraries and headers
make -f makefile.unix \
USE_TOR_EMBEDDED=1
You may need to adjust the -l flags in the makefile depending on the exact
library names Tor produces. Check src/tor/tor-src/ after building:
find tor/tor-src -name '*.a' | sort
On the imported release-0.4.9 checkout in this repo, the simplest working
link path is the aggregate libtor.a plus the normal dependency libraries.
Windows (triangles-qt.pro)
Add to triangles-qt.pro:
qmake "USE_TOR_EMBEDDED=1" \
"TOR_SOURCE_ROOT=src/tor/tor-src"
Both build systems now default to:
- source root:
src/tor/tor-src - include path:
src/tor/tor-src/src/feature/api - library path:
src/tor/tor-src - embedded Tor library:
-ltor
On Windows, the imported Tor 0.4.9.5 build also needed:
-llzma-lzstd-liphlpapi-lshlwapi(already linked by Triangles)
Step 4: Wire into init.cpp
The global hooks StartEmbeddedTor() and StopEmbeddedTor() need to be called
from init.cpp. Add these calls:
In AppInit2() (after network init, before starting node):
#include "tor/tor_embedded.h"
// Near the end of AppInit2, after network initialization:
if (!StartEmbeddedTor()) {
printf("WARNING: Embedded Tor failed to start. .onion connectivity unavailable.\n");
// Non-fatal: wallet works without Tor, just no .onion
}
In Shutdown():
StopEmbeddedTor();
Step 5: Configure SOCKS Proxy for Outbound Connections
After Tor starts, the wallet needs to route .onion connections through the
SOCKS5 proxy. In net.cpp, after Tor is initialized:
// If embedded Tor is running, use its SOCKS proxy for .onion addresses
CTorEmbedded* tor = CTorEmbedded::GetInstance();
if (tor->IsRunning()) {
// Set proxy for .onion connections
proxyType addrProxy(CService("127.0.0.1", tor->GetSocksPort()), 5);
SetNameProxy(addrProxy);
}
Runtime Flags
The embedded Tor respects these command-line flags:
| Flag | Default | Description |
|---|---|---|
-notor |
false | Disable Tor entirely |
-torsocks=PORT |
19099 | SOCKS5 proxy port |
-torhsport=PORT |
24112 | Hidden service virtual port |
File Layout After Integration
src/tor/
├── tor-src/ ← git submodule (official Tor repo)
│ └── src/
│ ├── lib/libtor-*.a
│ └── feature/api/tor_api.h
│ └── libtor.a
├── tor_embedded.h ← CTorEmbedded class header
├── tor_embedded.cpp ← implementation (calls tor_run_main)
├── tor_process.h ← external Tor process manager (fallback)
├── tor_process.cpp
├── onion_v3.h ← V3 onion address utilities
├── onion_v3.cpp
├── anonymize.h ← data dir helpers
├── anonymize.cpp
└── LICENSE
Reference: How VERGE (XVG) Does It
VERGE uses the same pattern. Their implementation is at:
src/torcontroller.cpp(~100 lines)- They use
tor_main()(older API, pre-0.4.5) - Git submodule at
src/tor/pointing torelease-0.4.8branch - Build Tor as part of their
depends/system
Key difference: modern Tor (0.4.5+) uses tor_run_main() with a configuration
object instead of raw tor_main(int argc, char** argv).
Troubleshooting
Tor fails to bootstrap: Check firewall rules. Tor needs outbound TCP to the Tor network (ports 80, 443, 9001, 9030).
Link errors with libtor: Prefer the aggregate libtor.a from the top level
of the Tor build tree. On the imported Windows/MSYS2 build in this repo, the
minimal verified link set was:
-ltor -levent -lssl -lcrypto -lz -llzma -lzstd -lws2_32 -liphlpapi -lshlwapi
OpenSSL version mismatch: Both Tor and Triangles must link against the same
OpenSSL version (3.x). If Tor was built against a different OpenSSL, rebuild it
with the same --with-openssl-dir.