Skip to content

Commit fce2b7b

Browse files
authored
Merge pull request #688 from Camillarhi/circuit-breaker-plugin
Circuit breaker plugin
2 parents 5de9f76 + 5905f45 commit fce2b7b

File tree

6 files changed

+239
-0
lines changed

6 files changed

+239
-0
lines changed

docs/circuit-breaker.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Circuit Breaker for Warnet
2+
3+
## Overview
4+
5+
Circuit Breaker is a Lightning Network firewall that protects LND nodes from being flooded with HTLCs. When integrated with Warnet, Circuit Breaker runs as a sidecar container alongside your LND nodes.
6+
7+
Circuit Breaker is to Lightning what firewalls are to the internet - it allows nodes to protect themselves by setting maximum limits on in-flight HTLCs on a per-peer basis and applying rate limits to forwarded HTLCs.
8+
9+
* **Repository**: https://github.com/lightningequipment/circuitbreaker
10+
* **Full Documentation**: See the main repository for detailed information about Circuit Breaker's features, operating modes, and configuration options
11+
12+
## Usage in Warnet
13+
14+
### Basic Configuration
15+
16+
To enable Circuit Breaker for an LND node in your `network.yaml` file, add the `circuitbreaker` section under the `lnd` configuration. When enabled, Circuit Breaker will automatically start as a sidecar container and connect to your LND node:
17+
18+
```yaml
19+
nodes:
20+
- name: tank-0003
21+
addnode:
22+
- tank-0000
23+
ln:
24+
lnd: true
25+
lnd:
26+
config: |
27+
bitcoin.timelockdelta=33
28+
channels:
29+
- id:
30+
block: 300
31+
index: 1
32+
target: tank-0004-ln
33+
capacity: 100000
34+
push_amt: 50000
35+
circuitbreaker:
36+
enabled: true # This enables Circuit Breaker for this node
37+
httpPort: 9235 # Can override default port per-node (optional)
38+
```
39+
40+
### Configuration Options
41+
42+
- `enabled`: Set to `true` to enable Circuit Breaker for the node
43+
- `httpPort`: Override the default HTTP port (9235) for the web UI (optional)
44+
45+
### Complete Example
46+
47+
Here's a complete `network.yaml` example with Circuit Breaker enabled on one node:
48+
49+
```yaml
50+
nodes:
51+
- name: tank-0000
52+
addnode:
53+
- tank-0001
54+
ln:
55+
lnd: true
56+
57+
- name: tank-0001
58+
addnode:
59+
- tank-0002
60+
ln:
61+
lnd: true
62+
63+
- name: tank-0002
64+
addnode:
65+
- tank-0000
66+
ln:
67+
lnd: true
68+
69+
- name: tank-0003
70+
addnode:
71+
- tank-0000
72+
ln:
73+
lnd: true
74+
lnd:
75+
config: |
76+
bitcoin.timelockdelta=33
77+
channels:
78+
- id:
79+
block: 300
80+
index: 1
81+
target: tank-0004-ln
82+
capacity: 100000
83+
push_amt: 50000
84+
circuitbreaker:
85+
enabled: true
86+
httpPort: 9235
87+
88+
- name: tank-0004
89+
addnode:
90+
- tank-0000
91+
ln:
92+
lnd: true
93+
lnd:
94+
channels:
95+
- id:
96+
block: 300
97+
index: 2
98+
target: tank-0005-ln
99+
capacity: 50000
100+
push_amt: 25000
101+
102+
- name: tank-0005
103+
addnode:
104+
- tank-0000
105+
ln:
106+
lnd: true
107+
```
108+
109+
## Accessing Circuit Breaker
110+
111+
Circuit Breaker provides both a web-based interface and REST API endpoints for configuration and monitoring.
112+
113+
### Web UI Access
114+
115+
To access the web interface:
116+
117+
1. **Port Forward to the Circuit Breaker service**:
118+
```bash
119+
kubectl port-forward pod/<node-name>-ln <local-port>:<httpPort>
120+
```
121+
122+
For example, if your node is named `tank-0003` and using the default port:
123+
```bash
124+
kubectl port-forward pod/tank-0003-ln 9235:9235
125+
```
126+
127+
2. **Open your browser** and navigate to:
128+
```
129+
http://localhost:9235
130+
```
131+
132+
3. **Configure your firewall rules** through the web interface:
133+
- Set per-peer HTLC limits
134+
- Configure rate limiting parameters
135+
- Choose operating modes
136+
- Monitor HTLC statistics
137+
138+
### API Access
139+
140+
You can also interact with Circuit Breaker programmatically using kubectl commands to access the REST API:
141+
142+
**Get node information:**
143+
```bash
144+
kubectl exec <node-name>-ln -c circuitbreaker -- wget -qO - 127.0.0.1:<httpPort>/api/info
145+
```
146+
147+
**Get current limits:**
148+
```bash
149+
kubectl exec <node-name>-ln -c circuitbreaker -- wget -qO - 127.0.0.1:<httpPort>/api/limits
150+
```
151+
152+
For example, with node `tank-0003-ln`:
153+
```bash
154+
kubectl exec tank-0003-ln -c circuitbreaker -- wget -qO - 127.0.0.1:9235/api/info
155+
kubectl exec tank-0003-ln -c circuitbreaker -- wget -qO - 127.0.0.1:9235/api/limits
156+
```
157+
158+
## Architecture
159+
160+
Circuit Breaker runs as a sidecar container alongside your LND node in Warnet:
161+
- **LND Container**: Runs your Lightning node
162+
- **Circuit Breaker Container**: Connects to LND via RPC and provides firewall functionality
163+
- **Shared Volume**: Allows Circuit Breaker to access LND's TLS certificates and macaroons
164+
- **Web Interface**: Accessible via port forwarding for configuration
165+
166+
## Requirements
167+
168+
- **LND Version**: 0.15.4-beta or above
169+
- **Warnet**: Compatible with standard Warnet LND deployments
170+
171+
## Support
172+
173+
For issues and questions:
174+
- Circuit Breaker Repository: https://github.com/lightningequipment/circuitbreaker
175+
- Warnet Documentation: Refer to the Warnet installation guides [install.md](install.md)
176+
- LND Documentation: https://docs.lightning.engineering/
177+
178+
---
179+
180+
*Circuit Breaker integration for Warnet enables sophisticated HTLC management and protection for Lightning Network nodes in test environments.*

resources/charts/bitcoincore/charts/lnd/templates/pod.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,37 @@ spec:
5858
- mountPath: /root/.lnd/tls.cert
5959
name: config
6060
subPath: tls.cert
61+
- name: shared-volume
62+
mountPath: /root/.lnd/
6163
{{- with .Values.extraContainers }}
6264
{{- toYaml . | nindent 4 }}
6365
{{- end }}
66+
{{- if .Values.circuitbreaker.enabled }}
67+
- name: circuitbreaker
68+
image: {{ .Values.circuitbreaker.image | quote }}
69+
imagePullPolicy: IfNotPresent
70+
args:
71+
- "--network={{ .Values.global.chain }}"
72+
- "--rpcserver=localhost:{{ .Values.RPCPort }}"
73+
- "--tlscertpath=/tls.cert"
74+
- "--macaroonpath=/root/.lnd/data/chain/bitcoin/{{ .Values.global.chain }}/admin.macaroon"
75+
- "--httplisten=0.0.0.0:{{ .Values.circuitbreaker.httpPort }}"
76+
volumeMounts:
77+
- name: shared-volume
78+
mountPath: /root/.lnd/
79+
- name: config
80+
mountPath: /tls.cert
81+
subPath: tls.cert
82+
{{- end }}
6483
volumes:
6584
{{- with .Values.volumes }}
6685
{{- toYaml . | nindent 4 }}
6786
{{- end }}
6887
- configMap:
6988
name: {{ include "lnd.fullname" . }}
7089
name: config
90+
- name: shared-volume
91+
emptyDir: {}
7192
{{- with .Values.nodeSelector }}
7293
nodeSelector:
7394
{{- toYaml . | nindent 4 }}

resources/charts/bitcoincore/charts/lnd/values.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,8 @@ config: ""
132132
defaultConfig: ""
133133

134134
channels: []
135+
136+
circuitbreaker:
137+
enabled: false # Default to disabled
138+
image: carlakirkcohen/circuitbreaker:attackathon-test
139+
httpPort: 9235

test/data/ln/network.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ nodes:
2121
target: tank-0004-ln
2222
capacity: 100000
2323
push_amt: 50000
24+
circuitbreaker:
25+
enabled: true
26+
httpPort: 9235
27+
2428
- name: tank-0004
2529
addnode:
2630
- tank-0000

test/data/network_with_plugins/network.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ nodes:
3232
target: tank-0004-ln
3333
capacity: 100000
3434
push_amt: 50000
35+
circuitbreaker:
36+
enabled: true # This enables circuitbreaker for this node
37+
httpPort: 9235 # Can override defaults per-node
3538

3639
- name: tank-0004
3740
addnode:
@@ -85,3 +88,4 @@ plugins: # Each plugin section has a number of hooks available (preDeploy, post
8588
entrypoint: "../plugins/hello"
8689
helloTo: "postNetwork!"
8790
podName: "hello-post-network"
91+

test/ln_basic_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
import os
5+
import subprocess
56
from pathlib import Path
67
from time import sleep
78

@@ -24,11 +25,18 @@ def __init__(self):
2425
"tank-0005-ln",
2526
]
2627

28+
self.cb_port = 9235
29+
self.cb_node = "tank-0003-ln"
30+
self.port_forward = None
31+
2732
def run_test(self):
2833
try:
2934
# Wait for all nodes to wake up. ln_init will start automatically
3035
self.setup_network()
3136

37+
# Test circuit breaker API
38+
self.test_circuit_breaker_api()
39+
3240
# Send a payment across channels opened automatically by ln_init
3341
self.pay_invoice(sender="tank-0005-ln", recipient="tank-0003-ln")
3442

@@ -120,6 +128,23 @@ def scenario_open_channels(self):
120128
self.log.info(f"Running scenario from: {scenario_file}")
121129
self.warnet(f"run {scenario_file} --source_dir={self.scen_dir} --debug")
122130

131+
def test_circuit_breaker_api(self):
132+
self.log.info("Testing Circuit Breaker API with direct kubectl commands")
133+
134+
# Test /info endpoint
135+
info_cmd = f"kubectl exec {self.cb_node} -c circuitbreaker -- wget -qO - 127.0.0.1:{self.cb_port}/api/info"
136+
info = json.loads(subprocess.check_output(info_cmd, shell=True).decode())
137+
assert "nodeKey" in info, "Circuit breaker info missing nodeKey"
138+
self.log.info(f"Got node info: {info}")
139+
140+
# Test /limits endpoint
141+
limits_cmd = f"kubectl exec {self.cb_node} -c circuitbreaker -- wget -qO - 127.0.0.1:{self.cb_port}/api/limits"
142+
limits = json.loads(subprocess.check_output(limits_cmd, shell=True).decode())
143+
assert "limits" in limits, "Circuit breaker limits missing"
144+
self.log.info(f"Got limits: {limits}")
145+
146+
self.log.info("✅ Circuit Breaker API tests passed")
147+
123148

124149
if __name__ == "__main__":
125150
test = LNBasicTest()

0 commit comments

Comments
 (0)