Skip to content

Commit ddb0b61

Browse files
committed
refactor(reactor): remove module-level global reactor
1 parent 27381c1 commit ddb0b61

32 files changed

+143
-93
lines changed

extras/custom_checks.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,26 @@ function check_do_not_import_from_hathor_in_entrypoints() {
101101
return 0
102102
}
103103

104+
function check_do_not_import_twisted_reactor_directly() {
105+
EXCLUDES="--exclude=reactor.py --exclude=conftest.py"
106+
PATTERN='\<.*from .*twisted.internet import .*reactor\>'
107+
108+
if grep -R $EXCLUDES "$PATTERN" "${SOURCE_DIRS[@]}"; then
109+
echo 'do not use `from twisted.internet import reactor` directly.'
110+
echo 'instead, use `hathor.reactor.get_global_reactor()`.'
111+
return 1
112+
fi
113+
return 0
114+
}
115+
104116
# List of functions to be executed
105117
checks=(
106118
check_version_match
107119
check_do_not_use_builtin_random_in_tests
108120
check_deprecated_typing
109121
check_do_not_import_tests_in_hathor
110122
check_do_not_import_from_hathor_in_entrypoints
123+
check_do_not_import_twisted_reactor_directly
111124
)
112125

113126
# Initialize a variable to track if any check fails

hathor/builder/builder.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from hathor.p2p.manager import ConnectionsManager
3535
from hathor.p2p.peer_id import PeerId
3636
from hathor.pubsub import PubSubManager
37+
from hathor.reactor import ReactorProtocol as Reactor
3738
from hathor.storage import RocksDBStorage
3839
from hathor.stratum import StratumFactory
3940
from hathor.transaction.storage import (
@@ -42,7 +43,7 @@
4243
TransactionRocksDBStorage,
4344
TransactionStorage,
4445
)
45-
from hathor.util import Random, Reactor, get_environment_info, not_none
46+
from hathor.util import Random, get_environment_info, not_none
4647
from hathor.verification.verification_service import VerificationService, VertexVerifiers
4748
from hathor.wallet import BaseWallet, Wallet
4849

@@ -311,7 +312,7 @@ def _get_or_create_pubsub(self) -> PubSubManager:
311312
return self._pubsub
312313

313314
def _create_stratum_server(self, manager: HathorManager) -> StratumFactory:
314-
stratum_factory = StratumFactory(manager=manager)
315+
stratum_factory = StratumFactory(manager=manager, reactor=self._get_reactor())
315316
manager.stratum_factory = stratum_factory
316317
manager.metrics.stratum_factory = stratum_factory
317318
return stratum_factory

hathor/builder/cli_builder.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@
3535
from hathor.p2p.peer_id import PeerId
3636
from hathor.p2p.utils import discover_hostname, get_genesis_short_hash
3737
from hathor.pubsub import PubSubManager
38+
from hathor.reactor import ReactorProtocol as Reactor
3839
from hathor.stratum import StratumFactory
39-
from hathor.util import Random, Reactor, not_none
40+
from hathor.util import Random, not_none
4041
from hathor.verification.verification_service import VerificationService
4142
from hathor.verification.vertex_verifiers import VertexVerifiers
4243
from hathor.wallet import BaseWallet, HDWallet, Wallet
@@ -271,7 +272,7 @@ def create_manager(self, reactor: Reactor) -> HathorManager:
271272
p2p_manager.set_manager(self.manager)
272273

273274
if self._args.stratum:
274-
stratum_factory = StratumFactory(self.manager)
275+
stratum_factory = StratumFactory(self.manager, reactor=reactor)
275276
self.manager.stratum_factory = stratum_factory
276277
self.manager.metrics.stratum_factory = stratum_factory
277278

hathor/builder/resources_builder.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,15 +224,15 @@ def create_resources(self) -> server.Site:
224224
root.putChild(b'_debug', debug_resource)
225225
resources.extend([
226226
(b'log', DebugLogResource(), debug_resource),
227-
(b'raise', DebugRaiseResource(), debug_resource),
228-
(b'reject', DebugRejectResource(), debug_resource),
227+
(b'raise', DebugRaiseResource(self.manager.reactor), debug_resource),
228+
(b'reject', DebugRejectResource(self.manager.reactor), debug_resource),
229229
(b'print', DebugPrintResource(), debug_resource),
230230
])
231231
if self._args.enable_crash_api:
232232
crash_resource = Resource()
233233
root.putChild(b'_crash', crash_resource)
234234
resources.extend([
235-
(b'exit', DebugCrashResource(), crash_resource),
235+
(b'exit', DebugCrashResource(self.manager.reactor), crash_resource),
236236
(b'mess_around', DebugMessAroundResource(self.manager), crash_resource),
237237
])
238238

hathor/cli/events_simulator/events_simulator.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,16 @@ def execute(args: Namespace) -> None:
4444
os.environ['HATHOR_CONFIG_YAML'] = UNITTESTS_SETTINGS_FILEPATH
4545
from hathor.cli.events_simulator.event_forwarding_websocket_factory import EventForwardingWebsocketFactory
4646
from hathor.cli.events_simulator.scenario import Scenario
47+
from hathor.reactor import get_global_reactor
4748
from hathor.simulator import Simulator
48-
from hathor.util import reactor
4949

5050
try:
5151
scenario = Scenario[args.scenario]
5252
except KeyError as e:
5353
possible_scenarios = [scenario.name for scenario in Scenario]
5454
raise ValueError(f'Invalid scenario "{args.scenario}". Choose one of {possible_scenarios}') from e
5555

56+
reactor = get_global_reactor()
5657
log = logger.new()
5758
simulator = Simulator(args.seed)
5859
simulator.start()

hathor/cli/run_node.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ def prepare(self, *, register_resources: bool = True) -> None:
138138
self.check_unsafe_arguments()
139139
self.check_python_version()
140140

141-
from hathor.util import reactor
141+
from hathor.reactor import get_global_reactor
142+
reactor = get_global_reactor()
142143
self.reactor = reactor
143144

144145
from hathor.builder import CliBuilder, ResourcesBuilder

hathor/cli/stratum_mining.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ def create_parser() -> ArgumentParser:
3030

3131
def execute(args: Namespace) -> None:
3232
from hathor.crypto.util import decode_address
33+
from hathor.reactor import get_global_reactor
3334
from hathor.stratum import StratumClient
34-
from hathor.util import reactor
3535
from hathor.wallet.exceptions import InvalidAddress
3636

3737
address = None
@@ -43,7 +43,8 @@ def execute(args: Namespace) -> None:
4343
print('The given address is invalid')
4444
sys.exit(-1)
4545

46-
miner = StratumClient(proc_count=args.nproc, address=address)
46+
reactor = get_global_reactor()
47+
miner = StratumClient(proc_count=args.nproc, address=address, reactor=reactor)
4748
miner.start()
4849
point = TCP4ClientEndpoint(reactor, args.host, args.port)
4950
connectProtocol(point, miner)

hathor/debug_resources.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
from hathor.cli.openapi_files.register import register_resource
2525
from hathor.exception import HathorError
2626
from hathor.manager import HathorManager
27-
from hathor.util import reactor
27+
from hathor.reactor import ReactorProtocol
2828
from hathor.utils.zope import asserted_cast
2929

3030
logger = get_logger()
@@ -54,6 +54,10 @@ class DebugRaiseResource(Resource):
5454
}
5555
default_msg = 'exception raised for debugging purposes'
5656

57+
def __init__(self, reactor: ReactorProtocol) -> None:
58+
super().__init__()
59+
self._reactor = reactor
60+
5761
def run(self, exc_cls: type[BaseException], msg: str) -> None:
5862
raise exc_cls(msg)
5963

@@ -63,7 +67,7 @@ def render_GET(self, request: Request) -> bytes:
6367
assert exc_cls_name in self.exc_class_map
6468
exc_cls = self.exc_class_map[exc_cls_name]
6569
msg = get_arg_default(raw_args, 'msg', self.default_msg)
66-
threaded_reactor = asserted_cast(IReactorFromThreads, reactor)
70+
threaded_reactor = asserted_cast(IReactorFromThreads, self._reactor)
6771
threaded_reactor.callFromThread(self.run, exc_cls, msg)
6872
return b'OK: no side-effects\n'
6973

@@ -188,7 +192,7 @@ def render_GET(self, request: Request) -> bytes:
188192
mess = get_arg_default(get_args(request), 'with', self.default_mess)
189193
assert mess in self.mess_map
190194
mess_func = self.mess_map[mess]
191-
threaded_reactor = asserted_cast(IReactorFromThreads, reactor)
195+
threaded_reactor = asserted_cast(IReactorFromThreads, self.manager.reactor)
192196
threaded_reactor.callFromThread(mess_func)
193197
return b'OK: database yanked, full-node will break\n'
194198

@@ -208,12 +212,16 @@ class DebugCrashResource(Resource):
208212
}
209213
}
210214

215+
def __init__(self, reactor: ReactorProtocol) -> None:
216+
super().__init__()
217+
self._reactor = reactor
218+
211219
def run(self, code: int) -> None:
212220
# XXX: sys.exit will raise a SystemExit exception that get's trapped by twisted
213221
# os._exit will bypass that by exiting directly, note that no cleanup methods will be called
214222
os._exit(code)
215223

216224
def render_GET(self, request: Request) -> bytes:
217225
code = get_arg_default(get_args(request), 'code', -1)
218-
reactor.callLater(1.0, self.run, code)
226+
self._reactor.callLater(1.0, self.run, code)
219227
return b'OK: full-node will exit and probably break database\n'

hathor/event/event_manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@
2323
from hathor.event.storage import EventStorage
2424
from hathor.event.websocket import EventWebsocketFactory
2525
from hathor.pubsub import EventArguments, HathorEvents, PubSubManager
26+
from hathor.reactor import ReactorProtocol as Reactor
2627
from hathor.transaction import BaseTransaction
27-
from hathor.util import Reactor, not_none, progress
28+
from hathor.util import not_none, progress
2829
from hathor.utils.iter import batch_iterator
2930

3031
logger = get_logger()

hathor/event/websocket/factory.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
from hathor.event.storage import EventStorage
2222
from hathor.event.websocket.protocol import EventWebsocketProtocol
2323
from hathor.event.websocket.response import EventResponse, InvalidRequestType
24-
from hathor.util import Reactor, not_none
24+
from hathor.reactor import ReactorProtocol as Reactor
25+
from hathor.util import not_none
2526

2627
logger = get_logger()
2728

hathor/manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,15 @@
5050
from hathor.p2p.protocol import HathorProtocol
5151
from hathor.profiler import get_cpu_profiler
5252
from hathor.pubsub import HathorEvents, PubSubManager
53+
from hathor.reactor import ReactorProtocol as Reactor
5354
from hathor.stratum import StratumFactory
5455
from hathor.transaction import BaseTransaction, Block, MergeMinedBlock, Transaction, TxVersion, sum_weights
5556
from hathor.transaction.exceptions import TxValidationError
5657
from hathor.transaction.storage import TransactionStorage
5758
from hathor.transaction.storage.exceptions import TransactionDoesNotExist
5859
from hathor.transaction.storage.tx_allow_scope import TxAllowScope
5960
from hathor.types import Address, VertexId
60-
from hathor.util import EnvironmentInfo, LogDuration, Random, Reactor, calculate_min_significant_weight, not_none
61+
from hathor.util import EnvironmentInfo, LogDuration, Random, calculate_min_significant_weight, not_none
6162
from hathor.verification.verification_service import VerificationService
6263
from hathor.wallet import BaseWallet
6364

hathor/metrics.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
from hathor.conf import HathorSettings
2323
from hathor.p2p.manager import ConnectionsManager, PeerConnectionsMetrics
2424
from hathor.pubsub import EventArguments, HathorEvents, PubSubManager
25+
from hathor.reactor import ReactorProtocol as Reactor
2526
from hathor.transaction.base_transaction import sum_weights
2627
from hathor.transaction.block import Block
2728
from hathor.transaction.storage import TransactionRocksDBStorage, TransactionStorage
2829
from hathor.transaction.storage.cache_storage import TransactionCacheStorage
29-
from hathor.util import Reactor
3030

3131
if TYPE_CHECKING:
3232
from hathor.stratum import StratumFactory # noqa: F401
@@ -63,7 +63,7 @@ class Metrics:
6363
connections: ConnectionsManager
6464
tx_storage: TransactionStorage
6565
# Twisted reactor that handles the time and callLater
66-
reactor: Optional[Reactor] = None
66+
reactor: Reactor
6767

6868
# Transactions count in the network
6969
transactions: int = 0
@@ -127,10 +127,6 @@ def __post_init__(self) -> None:
127127
# Stores caculated block weights saved in tx storage
128128
self.weight_block_deque: deque[WeightValue] = deque(maxlen=self.weight_block_deque_len)
129129

130-
if self.reactor is None:
131-
from hathor.util import reactor as twisted_reactor
132-
self.reactor = twisted_reactor
133-
134130
# A timer to periodically collect data
135131
self._lc_collect_data = LoopingCall(self._collect_data)
136132
self._lc_collect_data.clock = self.reactor

hathor/p2p/manager.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@
3434
from hathor.p2p.sync_version import SyncVersion
3535
from hathor.p2p.utils import description_to_connection_string, parse_whitelist
3636
from hathor.pubsub import HathorEvents, PubSubManager
37+
from hathor.reactor import ReactorProtocol as Reactor
3738
from hathor.transaction import BaseTransaction
38-
from hathor.util import Random, Reactor
39+
from hathor.util import Random
3940

4041
if TYPE_CHECKING:
4142
from twisted.internet.interfaces import IDelayedCall

hathor/p2p/netfilter/matches_remote.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from twisted.internet.task import LoopingCall
2121

2222
from hathor.p2p.netfilter.matches import NetfilterMatch, NetfilterMatchIPAddress
23-
from hathor.util import Reactor
23+
from hathor.reactor import ReactorProtocol as Reactor
2424

2525
if TYPE_CHECKING:
2626
from hathor.p2p.netfilter.context import NetfilterContext

hathor/p2p/rate_limiter.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
from typing import NamedTuple, Optional
1616

17-
from hathor.util import Reactor
17+
from hathor.reactor import ReactorProtocol as Reactor
1818

1919

2020
class RateLimiterLimit(NamedTuple):
@@ -32,12 +32,9 @@ class RateLimiter:
3232
# Stores the last hit for each key
3333
hits: dict[str, RateLimiterLimit]
3434

35-
def __init__(self, reactor: Optional[Reactor] = None):
35+
def __init__(self, reactor: Reactor):
3636
self.keys = {}
3737
self.hits = {}
38-
if reactor is None:
39-
from hathor.util import reactor as twisted_reactor
40-
reactor = twisted_reactor
4138
self.reactor = reactor
4239

4340
def set_limit(self, key: str, max_hits: int, window_seconds: float) -> None:

hathor/p2p/sync_factory.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,16 @@
1313
# limitations under the License.
1414

1515
from abc import ABC, abstractmethod
16-
from typing import TYPE_CHECKING, Optional
16+
from typing import TYPE_CHECKING
1717

1818
from hathor.p2p.sync_agent import SyncAgent
19-
from hathor.util import Reactor
19+
from hathor.reactor import ReactorProtocol as Reactor
2020

2121
if TYPE_CHECKING:
2222
from hathor.p2p.protocol import HathorProtocol
2323

2424

2525
class SyncAgentFactory(ABC):
2626
@abstractmethod
27-
def create_sync_agent(self, protocol: 'HathorProtocol', reactor: Optional[Reactor] = None) -> SyncAgent:
27+
def create_sync_agent(self, protocol: 'HathorProtocol', reactor: Reactor) -> SyncAgent:
2828
pass

hathor/p2p/sync_v1/agent.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@
2626
from hathor.p2p.messages import GetNextPayload, GetTipsPayload, NextPayload, ProtocolMessages, TipsPayload
2727
from hathor.p2p.sync_agent import SyncAgent
2828
from hathor.p2p.sync_v1.downloader import Downloader
29+
from hathor.reactor import ReactorProtocol as Reactor
2930
from hathor.transaction import BaseTransaction
3031
from hathor.transaction.base_transaction import tx_or_block_from_bytes
3132
from hathor.transaction.storage.exceptions import TransactionDoesNotExist
32-
from hathor.util import Reactor, json_dumps, json_loads
33+
from hathor.util import json_dumps, json_loads
3334

3435
logger = get_logger()
3536

@@ -59,7 +60,7 @@ class NodeSyncTimestamp(SyncAgent):
5960

6061
MAX_HASHES: int = 40
6162

62-
def __init__(self, protocol: 'HathorProtocol', downloader: Downloader, reactor: Optional[Reactor] = None) -> None:
63+
def __init__(self, protocol: 'HathorProtocol', downloader: Downloader, reactor: Reactor) -> None:
6364
"""
6465
:param protocol: Protocol of the connection.
6566
:type protocol: HathorProtocol
@@ -72,9 +73,6 @@ def __init__(self, protocol: 'HathorProtocol', downloader: Downloader, reactor:
7273
self.manager = protocol.node
7374
self.downloader = downloader
7475

75-
if reactor is None:
76-
from hathor.util import reactor as twisted_reactor
77-
reactor = twisted_reactor
7876
self.reactor: Reactor = reactor
7977

8078
# Rate limit for this connection.

hathor/p2p/sync_v1/factory.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from hathor.p2p.sync_factory import SyncAgentFactory
2020
from hathor.p2p.sync_v1.agent import NodeSyncTimestamp
2121
from hathor.p2p.sync_v1.downloader import Downloader
22-
from hathor.util import Reactor
22+
from hathor.reactor import ReactorProtocol as Reactor
2323

2424
if TYPE_CHECKING:
2525
from hathor.p2p.protocol import HathorProtocol
@@ -36,5 +36,5 @@ def get_downloader(self) -> Downloader:
3636
self._downloader = Downloader(self.connections.manager)
3737
return self._downloader
3838

39-
def create_sync_agent(self, protocol: 'HathorProtocol', reactor: Optional[Reactor] = None) -> SyncAgent:
39+
def create_sync_agent(self, protocol: 'HathorProtocol', reactor: Reactor) -> SyncAgent:
4040
return NodeSyncTimestamp(protocol, downloader=self.get_downloader(), reactor=reactor)

0 commit comments

Comments
 (0)