Tor support#1336
Conversation
99f0712 to
2d15a97
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1336 +/- ##
==========================================
Coverage 100.00% 100.00%
==========================================
Files 211 212 +1
Lines 7014 7276 +262
Branches 1398 1426 +28
==========================================
+ Hits 7014 7276 +262 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Hey @Jem256 This is a fantastic feature. We've received many requests for Tor support over the year. Thanks you so much for tackling this. I've done some functional testing and have a bit of feedback/questions:
|
|
Thanks for the PR @Jem256. I also did some functional tests.
Questions:
I will look deeply into the code but for now these are my observations. |
|
This is not the correct behaviour. I realised my current implementation is hybrid instead of Tor only. I'll improve this |
Terminal is just a wrapper around LND (plus the other daemons). LND is running inside of the Terminal process. So all of the LND config flags works for Terminal. You just have to add an |
476c6b1 to
eb45f9e
Compare
Greptile SummaryThis PR adds comprehensive Tor support across all node types in Polar (bitcoind, LND, Core Lightning, Eclair, litd), enabling users to test .onion services in their local Lightning Network simulations. The implementation spans Docker configuration, state management, UI components, and service layer changes. Key changes:
Issues found:
Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| src/store/models/network.ts | Core Tor toggle logic for network and individual nodes. Missing await on actions.save() in toggleTorForNode (line 1373) creates a race condition. Moved connectPeers and getInfo out of bitcoin node startup and added Tor-aware delays. |
| src/utils/network.ts | Added applyTorFlags, getEffectiveCommand, supportsTor utilities. The -onlynet=onion flag for bitcoind may prevent mixed-mode peer connectivity in the Docker network. |
| src/store/models/bitcoin.ts | Added connectAllPeers thunk and getNetworkInfo integration. The peer connection logic correctly resolves onion addresses when both peers have Tor enabled, falling back to Docker hostnames otherwise. |
| src/lib/docker/composeFile.ts | Added Tor flag application and ENABLE_TOR env variable to all node types (bitcoind, LND, CLN, Eclair, litd). Consistent pattern across all add* methods. |
| src/lib/bitcoin/bitcoind/bitcoindService.ts | Added getNetworkInfo method extracting onion addresses from localaddresses. Changed connectPeers to accept explicit peer addresses instead of using node.peers. |
| src/lib/bitcoin/notImplementedService.ts | Added getNetworkInfo stub, but connectPeers signature doesn't match the updated BitcoinService interface (missing peerAddresses parameter). |
| src/components/designer/bitcoin/ConnectTab.tsx | Uses dynamic P2P host from node state (onion or clearnet). The p2pHost value can be undefined before node info loads, which would pass "undefined" to the copy icon. |
| src/components/designer/lightning/ConnectTab.tsx | Added p2pUriExternal function that returns the internal Tor rpcUrl when Tor is enabled, or the clearnet URI otherwise. Applied consistently across all lightning implementations. |
| src/components/common/TorButton.tsx | New component providing per-node Tor enable/disable with confirmation modals and restart warnings. Clean implementation with proper state handling. |
| src/components/network/NetworkActions.tsx | Added network-wide Tor toggle switch in the dropdown menu. Correctly disables the switch when the network is started. Uses supportsTor to determine eligibility. |
| docker/bitcoind/docker-entrypoint.sh | Added Tor daemon setup with hidden service. Unconditional usermod may fail if debian-tor group doesn't exist, unlike the eclair entrypoint which has a guard. |
| docker/lnd/docker-entrypoint.sh | Added Tor daemon setup with hidden service for LND P2P and REST ports. Same unconditional usermod issue as bitcoind entrypoint. |
| docker/eclair/docker-entrypoint.sh | Added Tor setup with proper group existence guard. Correctly skips public IP announcement when Tor is enabled. Best-implemented entrypoint of the set. |
| docker/litd/docker-entrypoint.sh | Added Tor setup for litd. Uses chmod 755 on /var/lib/tor while all others use chmod 700 — inconsistent and less secure. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User toggles Tor] --> B{Network-wide or Per-node?}
B -->|Network-wide| C[NetworkActions: handleTorToggle]
B -->|Per-node| D[TorButton: showConfirmModal]
C --> E[network.toggleTorForNetwork]
E --> F[setAllNodesTor - set enableTor on all nodes]
F --> G[save network state]
G --> H[saveComposeFile - regenerate docker-compose.yml]
D --> I[network.toggleTorForNode]
I --> J{Node started?}
J -->|Yes| K[toggleNode - stop node]
J -->|No| L[setNodeTor - set enableTor]
K --> L
L --> M[save network state]
M --> N[saveComposeFile]
N --> O{Was started?}
O -->|Yes| P[toggleNode - restart node]
O -->|No| Q[Done]
P --> Q
H --> R[ComposeFile: applyTorFlags + ENABLE_TOR env]
N --> R
R --> S[Docker entrypoint: conditionally start Tor daemon]
S --> T{ENABLE_TOR=true?}
T -->|Yes| U[Start Tor + Hidden Service]
T -->|No| V[Skip Tor setup]
style A fill:#f9f,stroke:#333
style Q fill:#9f9,stroke:#333
style U fill:#ff9,stroke:#333
Last reviewed commit: 759415b
Additional Comments (1)
The |
This was done.
All nodes are now supported. However, opening channels in Eclair is crushing. Related to #1212 This is something i am investigating.
Tor processes are slow and this is what affects the syncing. I have increased the delay time on
This was done.
This was improved. Channels don't throw the icon placement off anymore.
|
This is now working. However, syncing is a bit slow because tor is slow. I'd appreciate suggestions on how to improve this
This is now working.
This was implemented.
Outbound peers ( cc @Abdulkbk |
Abdulkbk
left a comment
There was a problem hiding this comment.
Looking good 👍.
I have tested with bitcoind, lnd, and cln. I've not tested with eclair yet. I left some feedback.
Abdulkbk
left a comment
There was a problem hiding this comment.
Nice work so far, getting there...
I tested the functionality and observed some race conditions between Tor (bootstrapping) and the startup of LN nodes. This occasionally prevents nodes from discovering or connecting to peers. For instance, I ran with three LND nodes, and sometimes peers connect successfully, while other times they do not. I suspect we need to ensure Tor has fully started and bootstrapped in docker-entry.sh before launching the LN nodes.
Abdulkbk
left a comment
There was a problem hiding this comment.
This is really approaching the finish line quickly. I left some comments
| /** | ||
| * Adds or removes Tor flags from an LND command | ||
| */ | ||
| export const applyTorFlags = (command: string, enableTor: boolean): string => { |
There was a problem hiding this comment.
I think we can do without enableTor: boolean. The function's name is applyTorFlags, and it should only be called on nodes that support Tor and have Tor enabled.
There was a problem hiding this comment.
applyTorFlags is also called with enableTor: false in updateAdvancedOptions to strip Tor flags from user-edited commands before saving and in addBitcoind, addLnd etc where enableTor may be false. So the parameter is needed to handle both adding and removing Tor flags. Maybe I can rename it more meaningfully. (I've renamed it to updateTorFlags )
| ...updatedNetwork.nodes.bitcoin, | ||
| ].find(n => n.name === name); | ||
| if (updatedNode) { | ||
| await actions.toggleNode(updatedNode); |
There was a problem hiding this comment.
why not just pass the node supplied in this thunk?
There was a problem hiding this comment.
The original node from the thunk argument has stale state. The re-fetch is necessary because toggleNode uses node.status to decide whether to start or stop, and the original node still has Status.Started after being stopped.
| /** | ||
| * Check if a node implementation supports Tor | ||
| */ | ||
| export const supportsTor = (node: CommonNode): boolean => { |
There was a problem hiding this comment.
Looking at this again, I think the previous implementation where we explicitly check support for all nodes has its merits, but I'm open to others' opinions.
There was a problem hiding this comment.
I understand what you mean. My reason for changing the implementation was the fact that all current implementations of lightning and bitcoin that i am aware of support Tor. So i felt doing it explicitly was regurtating this. I am also open to other opinions
- Implement toggleTorForNetwork action to update all LND nodes - Create applyTorFlags utility to manage Tor command flags - Update Advanced Options to display effective command with Tor flags - Tor flags added dynamically during compose generation - ui for enable tor for all nodes
Extends existing Tor functionality to Bitcoin Core nodes. Refactors applyTorFlags to handle multiple implementations and updates Docker compose generation to conditionally apply bitcoind Tor flags based on node.enableTor setting.
- Extends existing Tor functionality to Core lightning nodes. - update getInfo service to fetch tor address
Add test coverage for Tor network toggle functionality, environment variables, and edge cases for various node types.
Add ability to enable/disable Tor for individual nodes through context menu. When toggling Tor on a running node, automatically stops, updates settings, and restarts the node. Includes UI updates to show Tor status with icon.
- Add supportsTor() helper to check Tor compatibility - Show "not supported" message for tap nodes - Hide Tor menu items for unsupported nodes - Simplify Tor-related functions using new helper
Extends existing Tor functionality to eclair lightning nodes.
Extends existing Tor functionality to terminal lightning nodes.
…k toggle when started - New nodes inherit network's Tor setting when added via drag-and-drop - Network-wide Tor toggle disabled when network is running
- Adds getNetworkInfo() method to retrieve network details from bitcoind nodes, including p2pHost detection for both clearnet and Tor addresses. Formats long Tor v3 addresses using ellipsis for better UI display. Updates store models and UI components to display connection details. Updates connectPeers to use onion addresses
- Add bitcoind healthcheck to compose so all lightning nodes wait until bitcoind RPC is ready before starting (service_healthy condition) - Clear app cache before starting network containers to avoid stale state - Extend LND waitForNodes timeout to 240s when Tor is enabled (vs 120s) to account for slower Tor circuit establishment - Evict broken LND gRPC clients from cache on error so retries get a fresh connection instead of reusing a failed one


Closes #219
Description
This PR adds Tor support for both Lightning Network and Bitcoin nodes, enabling users to test and use .onion services for connectivity. Provides a convenient setup for experimenting with Tor-based networks in a local or containerized environment.
Tor Support Implementation Checklist
Steps to Test
Flow 1: Create network → toggle Tor ON/OFF for all nodes → start network
Flow 2: Create network → start network (TOR OFF) → modify individual node to enable Tor → restart node
TODO
Push new images to Docker Hub for all node versions currently supported by Polar
Screenshots