Files
triangles_v5/CODEX-TOR-GUIDE.md
T
sami7777 39e244a11c Fix build: random_shuffle removal, Windows daemon missing objects
- 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>
2026-03-19 13:47:42 -07:00

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.a
  • src/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 to release-0.4.8 branch
  • 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.