Skip to content

Commit b46dae7

Browse files
authored
Merge pull request #917 from parth-soni07/refactor/replace-magic-numbers-with-named-constants
Refactor: Replace magic numbers with named constants and enums for clarity and maintainability
2 parents 066c875 + 17c1ced commit b46dae7

File tree

7 files changed

+281
-75
lines changed

7 files changed

+281
-75
lines changed

libp2p/relay/circuit_v2/config.py

Lines changed: 117 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
dataclass,
1010
field,
1111
)
12+
from enum import Flag, auto
1213

1314
from libp2p.peer.peerinfo import (
1415
PeerInfo,
@@ -18,38 +19,127 @@
1819
RelayLimits,
1920
)
2021

22+
DEFAULT_MIN_RELAYS = 3
23+
DEFAULT_MAX_RELAYS = 20
24+
DEFAULT_DISCOVERY_INTERVAL = 300 # seconds
25+
DEFAULT_RESERVATION_TTL = 3600 # seconds
26+
DEFAULT_MAX_CIRCUIT_DURATION = 3600 # seconds
27+
DEFAULT_MAX_CIRCUIT_BYTES = 1024 * 1024 * 1024 # 1GB
28+
29+
DEFAULT_MAX_CIRCUIT_CONNS = 8
30+
DEFAULT_MAX_RESERVATIONS = 4
31+
32+
MAX_RESERVATIONS_PER_IP = 8
33+
MAX_CIRCUITS_PER_IP = 16
34+
RESERVATION_RATE_PER_IP = 4 # per minute
35+
CIRCUIT_RATE_PER_IP = 8 # per minute
36+
MAX_CIRCUITS_TOTAL = 64
37+
MAX_RESERVATIONS_TOTAL = 32
38+
MAX_BANDWIDTH_PER_CIRCUIT = 1024 * 1024 # 1MB/s
39+
MAX_BANDWIDTH_TOTAL = 10 * 1024 * 1024 # 10MB/s
40+
41+
MIN_RELAY_SCORE = 0.5
42+
MAX_RELAY_LATENCY = 1.0 # seconds
43+
ENABLE_AUTO_RELAY = True
44+
AUTO_RELAY_TIMEOUT = 30 # seconds
45+
MAX_AUTO_RELAY_ATTEMPTS = 3
46+
RESERVATION_REFRESH_THRESHOLD = 0.8 # Refresh at 80% of TTL
47+
MAX_CONCURRENT_RESERVATIONS = 2
48+
49+
# Timeout constants for different components
50+
DEFAULT_DISCOVERY_STREAM_TIMEOUT = 10 # seconds
51+
DEFAULT_PEER_PROTOCOL_TIMEOUT = 5 # seconds
52+
DEFAULT_PROTOCOL_READ_TIMEOUT = 15 # seconds
53+
DEFAULT_PROTOCOL_WRITE_TIMEOUT = 15 # seconds
54+
DEFAULT_PROTOCOL_CLOSE_TIMEOUT = 10 # seconds
55+
DEFAULT_DCUTR_READ_TIMEOUT = 30 # seconds
56+
DEFAULT_DCUTR_WRITE_TIMEOUT = 30 # seconds
57+
DEFAULT_DIAL_TIMEOUT = 10 # seconds
58+
59+
60+
@dataclass
61+
class TimeoutConfig:
62+
"""Timeout configuration for different Circuit Relay v2 components."""
63+
64+
# Discovery timeouts
65+
discovery_stream_timeout: int = DEFAULT_DISCOVERY_STREAM_TIMEOUT
66+
peer_protocol_timeout: int = DEFAULT_PEER_PROTOCOL_TIMEOUT
67+
68+
# Core protocol timeouts
69+
protocol_read_timeout: int = DEFAULT_PROTOCOL_READ_TIMEOUT
70+
protocol_write_timeout: int = DEFAULT_PROTOCOL_WRITE_TIMEOUT
71+
protocol_close_timeout: int = DEFAULT_PROTOCOL_CLOSE_TIMEOUT
72+
73+
# DCUtR timeouts
74+
dcutr_read_timeout: int = DEFAULT_DCUTR_READ_TIMEOUT
75+
dcutr_write_timeout: int = DEFAULT_DCUTR_WRITE_TIMEOUT
76+
dial_timeout: int = DEFAULT_DIAL_TIMEOUT
77+
78+
79+
# Relay roles enum
80+
class RelayRole(Flag):
81+
"""
82+
Bit-flag enum that captures the three possible relay capabilities.
83+
84+
A node can combine multiple roles using bit-wise OR, for example::
85+
86+
RelayRole.HOP | RelayRole.STOP
87+
"""
88+
89+
HOP = auto() # Act as a relay for others ("hop")
90+
STOP = auto() # Accept relayed connections ("stop")
91+
CLIENT = auto() # Dial through existing relays ("client")
92+
2193

2294
@dataclass
2395
class RelayConfig:
2496
"""Configuration for Circuit Relay v2."""
2597

26-
# Role configuration
27-
enable_hop: bool = False # Whether to act as a relay (hop)
28-
enable_stop: bool = True # Whether to accept relayed connections (stop)
29-
enable_client: bool = True # Whether to use relays for dialing
98+
# Role configuration (bit-flags)
99+
roles: RelayRole = RelayRole.STOP | RelayRole.CLIENT
30100

31101
# Resource limits
32102
limits: RelayLimits | None = None
33103

34104
# Discovery configuration
35105
bootstrap_relays: list[PeerInfo] = field(default_factory=list)
36-
min_relays: int = 3
37-
max_relays: int = 20
38-
discovery_interval: int = 300 # seconds
106+
min_relays: int = DEFAULT_MIN_RELAYS
107+
max_relays: int = DEFAULT_MAX_RELAYS
108+
discovery_interval: int = DEFAULT_DISCOVERY_INTERVAL
39109

40110
# Connection configuration
41-
reservation_ttl: int = 3600 # seconds
42-
max_circuit_duration: int = 3600 # seconds
43-
max_circuit_bytes: int = 1024 * 1024 * 1024 # 1GB
111+
reservation_ttl: int = DEFAULT_RESERVATION_TTL
112+
max_circuit_duration: int = DEFAULT_MAX_CIRCUIT_DURATION
113+
max_circuit_bytes: int = DEFAULT_MAX_CIRCUIT_BYTES
114+
115+
# Timeout configuration
116+
timeouts: TimeoutConfig = field(default_factory=TimeoutConfig)
117+
118+
# ---------------------------------------------------------------------
119+
# Backwards-compat boolean helpers. Existing code that still accesses
120+
# ``cfg.enable_hop, cfg.enable_stop, cfg.enable_client`` will continue to work.
121+
# ---------------------------------------------------------------------
122+
123+
@property
124+
def enable_hop(self) -> bool: # pragma: no cover – helper
125+
return bool(self.roles & RelayRole.HOP)
126+
127+
@property
128+
def enable_stop(self) -> bool: # pragma: no cover – helper
129+
return bool(self.roles & RelayRole.STOP)
130+
131+
@property
132+
def enable_client(self) -> bool: # pragma: no cover – helper
133+
return bool(self.roles & RelayRole.CLIENT)
44134

45135
def __post_init__(self) -> None:
46136
"""Initialize default values."""
47137
if self.limits is None:
48138
self.limits = RelayLimits(
49139
duration=self.max_circuit_duration,
50140
data=self.max_circuit_bytes,
51-
max_circuit_conns=8,
52-
max_reservations=4,
141+
max_circuit_conns=DEFAULT_MAX_CIRCUIT_CONNS,
142+
max_reservations=DEFAULT_MAX_RESERVATIONS,
53143
)
54144

55145

@@ -58,35 +148,35 @@ class HopConfig:
58148
"""Configuration specific to relay (hop) nodes."""
59149

60150
# Resource limits per IP
61-
max_reservations_per_ip: int = 8
62-
max_circuits_per_ip: int = 16
151+
max_reservations_per_ip: int = MAX_RESERVATIONS_PER_IP
152+
max_circuits_per_ip: int = MAX_CIRCUITS_PER_IP
63153

64154
# Rate limiting
65-
reservation_rate_per_ip: int = 4 # per minute
66-
circuit_rate_per_ip: int = 8 # per minute
155+
reservation_rate_per_ip: int = RESERVATION_RATE_PER_IP
156+
circuit_rate_per_ip: int = CIRCUIT_RATE_PER_IP
67157

68158
# Resource quotas
69-
max_circuits_total: int = 64
70-
max_reservations_total: int = 32
159+
max_circuits_total: int = MAX_CIRCUITS_TOTAL
160+
max_reservations_total: int = MAX_RESERVATIONS_TOTAL
71161

72162
# Bandwidth limits
73-
max_bandwidth_per_circuit: int = 1024 * 1024 # 1MB/s
74-
max_bandwidth_total: int = 10 * 1024 * 1024 # 10MB/s
163+
max_bandwidth_per_circuit: int = MAX_BANDWIDTH_PER_CIRCUIT
164+
max_bandwidth_total: int = MAX_BANDWIDTH_TOTAL
75165

76166

77167
@dataclass
78168
class ClientConfig:
79169
"""Configuration specific to relay clients."""
80170

81171
# Relay selection
82-
min_relay_score: float = 0.5
83-
max_relay_latency: float = 1.0 # seconds
172+
min_relay_score: float = MIN_RELAY_SCORE
173+
max_relay_latency: float = MAX_RELAY_LATENCY
84174

85175
# Auto-relay settings
86-
enable_auto_relay: bool = True
87-
auto_relay_timeout: int = 30 # seconds
88-
max_auto_relay_attempts: int = 3
176+
enable_auto_relay: bool = ENABLE_AUTO_RELAY
177+
auto_relay_timeout: int = AUTO_RELAY_TIMEOUT
178+
max_auto_relay_attempts: int = MAX_AUTO_RELAY_ATTEMPTS
89179

90180
# Reservation management
91-
reservation_refresh_threshold: float = 0.8 # Refresh at 80% of TTL
92-
max_concurrent_reservations: int = 2
181+
reservation_refresh_threshold: float = RESERVATION_REFRESH_THRESHOLD
182+
max_concurrent_reservations: int = MAX_CONCURRENT_RESERVATIONS

libp2p/relay/circuit_v2/dcutr.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
from libp2p.peer.peerinfo import (
3030
PeerInfo,
3131
)
32+
from libp2p.relay.circuit_v2.config import (
33+
DEFAULT_DCUTR_READ_TIMEOUT,
34+
DEFAULT_DCUTR_WRITE_TIMEOUT,
35+
DEFAULT_DIAL_TIMEOUT,
36+
)
3237
from libp2p.relay.circuit_v2.nat import (
3338
ReachabilityChecker,
3439
)
@@ -47,11 +52,7 @@
4752
# Maximum message size for DCUtR (4KiB as per spec)
4853
MAX_MESSAGE_SIZE = 4 * 1024
4954

50-
# Timeouts
51-
STREAM_READ_TIMEOUT = 30 # seconds
52-
STREAM_WRITE_TIMEOUT = 30 # seconds
53-
DIAL_TIMEOUT = 10 # seconds
54-
55+
# DCUtR protocol constants
5556
# Maximum number of hole punch attempts per peer
5657
MAX_HOLE_PUNCH_ATTEMPTS = 5
5758

@@ -70,18 +71,33 @@ class DCUtRProtocol(Service):
7071
hole punching, after they have established an initial connection through a relay.
7172
"""
7273

73-
def __init__(self, host: IHost):
74+
def __init__(
75+
self,
76+
host: IHost,
77+
read_timeout: int = DEFAULT_DCUTR_READ_TIMEOUT,
78+
write_timeout: int = DEFAULT_DCUTR_WRITE_TIMEOUT,
79+
dial_timeout: int = DEFAULT_DIAL_TIMEOUT,
80+
):
7481
"""
7582
Initialize the DCUtR protocol.
7683
7784
Parameters
7885
----------
7986
host : IHost
8087
The libp2p host this protocol is running on
88+
read_timeout : int
89+
Timeout for stream read operations, in seconds
90+
write_timeout : int
91+
Timeout for stream write operations, in seconds
92+
dial_timeout : int
93+
Timeout for dial operations, in seconds
8194
8295
"""
8396
super().__init__()
8497
self.host = host
98+
self.read_timeout = read_timeout
99+
self.write_timeout = write_timeout
100+
self.dial_timeout = dial_timeout
85101
self.event_started = trio.Event()
86102
self._hole_punch_attempts: dict[ID, int] = {}
87103
self._direct_connections: set[ID] = set()
@@ -161,7 +177,7 @@ async def _handle_dcutr_stream(self, stream: INetStream) -> None:
161177

162178
try:
163179
# Read the CONNECT message
164-
with trio.fail_after(STREAM_READ_TIMEOUT):
180+
with trio.fail_after(self.read_timeout):
165181
msg_bytes = await stream.read(MAX_MESSAGE_SIZE)
166182

167183
# Parse the message
@@ -196,7 +212,7 @@ async def _handle_dcutr_stream(self, stream: INetStream) -> None:
196212
response.type = HolePunch.CONNECT
197213
response.ObsAddrs.extend(our_addrs)
198214

199-
with trio.fail_after(STREAM_WRITE_TIMEOUT):
215+
with trio.fail_after(self.write_timeout):
200216
await stream.write(response.SerializeToString())
201217

202218
logger.debug(
@@ -206,7 +222,7 @@ async def _handle_dcutr_stream(self, stream: INetStream) -> None:
206222
)
207223

208224
# Wait for SYNC message
209-
with trio.fail_after(STREAM_READ_TIMEOUT):
225+
with trio.fail_after(self.read_timeout):
210226
sync_bytes = await stream.read(MAX_MESSAGE_SIZE)
211227

212228
# Parse the SYNC message
@@ -300,7 +316,7 @@ async def initiate_hole_punch(self, peer_id: ID) -> bool:
300316
connect_msg.ObsAddrs.extend(our_addrs)
301317

302318
start_time = time.time()
303-
with trio.fail_after(STREAM_WRITE_TIMEOUT):
319+
with trio.fail_after(self.write_timeout):
304320
await stream.write(connect_msg.SerializeToString())
305321

306322
logger.debug(
@@ -310,7 +326,7 @@ async def initiate_hole_punch(self, peer_id: ID) -> bool:
310326
)
311327

312328
# Receive the peer's CONNECT message
313-
with trio.fail_after(STREAM_READ_TIMEOUT):
329+
with trio.fail_after(self.read_timeout):
314330
resp_bytes = await stream.read(MAX_MESSAGE_SIZE)
315331

316332
# Calculate RTT
@@ -349,7 +365,7 @@ async def initiate_hole_punch(self, peer_id: ID) -> bool:
349365
sync_msg = HolePunch()
350366
sync_msg.type = HolePunch.SYNC
351367

352-
with trio.fail_after(STREAM_WRITE_TIMEOUT):
368+
with trio.fail_after(self.write_timeout):
353369
await stream.write(sync_msg.SerializeToString())
354370

355371
logger.debug("Sent SYNC message to %s", peer_id)
@@ -468,7 +484,7 @@ async def _dial_peer(self, peer_id: ID, addr: Multiaddr) -> None:
468484
peer_info = PeerInfo(peer_id, [addr])
469485

470486
# Try to connect with timeout
471-
with trio.fail_after(DIAL_TIMEOUT):
487+
with trio.fail_after(self.dial_timeout):
472488
await self.host.connect(peer_info)
473489

474490
logger.info("Successfully connected to %s at %s", peer_id, addr)

0 commit comments

Comments
 (0)