Skip to content

Commit 9bce2fa

Browse files
authored
Merge pull request #1114 from HathorNetwork/refactor/p2p-peer-use-peer-id
refactor(p2p): use PeerId type instead of str
2 parents 2c817fd + ada19b8 commit 9bce2fa

21 files changed

+96
-70
lines changed

hathor/builder/builder.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
TransactionStorage,
4848
)
4949
from hathor.transaction.vertex_parser import VertexParser
50-
from hathor.util import Random, get_environment_info, not_none
50+
from hathor.util import Random, get_environment_info
5151
from hathor.verification.verification_service import VerificationService
5252
from hathor.verification.vertex_verifiers import VertexVerifiers
5353
from hathor.vertex_handler import VertexHandler
@@ -264,7 +264,7 @@ def build(self) -> BuildArtifacts:
264264
rng=self._rng,
265265
checkpoints=self._checkpoints,
266266
capabilities=self._capabilities,
267-
environment_info=get_environment_info(self._cmdline, peer.id),
267+
environment_info=get_environment_info(self._cmdline, str(peer.id)),
268268
bit_signaling_service=bit_signaling_service,
269269
verification_service=verification_service,
270270
cpu_mining_service=cpu_mining_service,
@@ -515,7 +515,7 @@ def _get_or_create_event_manager(self) -> EventManager:
515515
reactor = self._get_reactor()
516516
storage = self._get_or_create_event_storage()
517517
factory = EventWebsocketFactory(
518-
peer_id=not_none(peer.id),
518+
peer_id=str(peer.id),
519519
network=settings.NETWORK_NAME,
520520
reactor=reactor,
521521
event_storage=storage,

hathor/builder/cli_builder.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
from hathor.reactor import ReactorProtocol as Reactor
4343
from hathor.stratum import StratumFactory
4444
from hathor.transaction.vertex_parser import VertexParser
45-
from hathor.util import Random, not_none
45+
from hathor.util import Random
4646
from hathor.verification.verification_service import VerificationService
4747
from hathor.verification.vertex_verifiers import VertexVerifiers
4848
from hathor.vertex_handler import VertexHandler
@@ -225,7 +225,7 @@ def create_manager(self, reactor: Reactor) -> HathorManager:
225225

226226
if self._args.x_enable_event_queue:
227227
self.event_ws_factory = EventWebsocketFactory(
228-
peer_id=not_none(peer.id),
228+
peer_id=str(peer.id),
229229
network=network,
230230
reactor=reactor,
231231
event_storage=event_storage
@@ -354,7 +354,7 @@ def create_manager(self, reactor: Reactor) -> HathorManager:
354354
event_manager=event_manager,
355355
wallet=self.wallet,
356356
checkpoints=settings.CHECKPOINTS,
357-
environment_info=get_environment_info(args=str(self._args), peer_id=peer.id),
357+
environment_info=get_environment_info(args=str(self._args), peer_id=str(peer.id)),
358358
full_verification=full_verification,
359359
enable_event_queue=self._args.x_enable_event_queue,
360360
bit_signaling_service=bit_signaling_service,

hathor/manager.py

+5-4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from hathor.mining.cpu_mining_service import CpuMiningService
4848
from hathor.p2p.manager import ConnectionsManager
4949
from hathor.p2p.peer import Peer
50+
from hathor.p2p.peer_id import PeerId
5051
from hathor.profiler import get_cpu_profiler
5152
from hathor.pubsub import HathorEvents, PubSubManager
5253
from hathor.reactor import ReactorProtocol as Reactor
@@ -225,7 +226,7 @@ def __init__(
225226
self._full_verification = full_verification
226227

227228
# List of whitelisted peers
228-
self.peers_whitelist: list[str] = []
229+
self.peers_whitelist: list[PeerId] = []
229230

230231
# List of capabilities of the peer
231232
if capabilities is not None:
@@ -297,7 +298,7 @@ def start(self) -> None:
297298
sys.exit(-1)
298299

299300
if self._enable_event_queue:
300-
self._event_manager.start(not_none(self.my_peer.id))
301+
self._event_manager.start(str(not_none(self.my_peer.id)))
301302

302303
self.state = self.NodeState.INITIALIZING
303304
self.pubsub.publish(HathorEvents.MANAGER_ON_START)
@@ -976,7 +977,7 @@ def on_new_tx(
976977
def has_sync_version_capability(self) -> bool:
977978
return self._settings.CAPABILITY_SYNC_VERSION in self.capabilities
978979

979-
def add_peer_to_whitelist(self, peer_id: str) -> None:
980+
def add_peer_to_whitelist(self, peer_id: PeerId) -> None:
980981
if not self._settings.ENABLE_PEER_WHITELIST:
981982
return
982983

@@ -985,7 +986,7 @@ def add_peer_to_whitelist(self, peer_id: str) -> None:
985986
else:
986987
self.peers_whitelist.append(peer_id)
987988

988-
def remove_peer_from_whitelist_and_disconnect(self, peer_id: str) -> None:
989+
def remove_peer_from_whitelist_and_disconnect(self, peer_id: PeerId) -> None:
989990
if not self._settings.ENABLE_PEER_WHITELIST:
990991
return
991992

hathor/metrics.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def collect_peer_connection_metrics(self) -> None:
253253

254254
metric = PeerConnectionMetrics(
255255
connection_string=str(connection.entrypoint) if connection.entrypoint else "",
256-
peer_id=connection.peer.id,
256+
peer_id=str(connection.peer.id),
257257
network=connection.network,
258258
received_messages=connection.metrics.received_messages,
259259
sent_messages=connection.metrics.sent_messages,

hathor/p2p/entrypoint.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,14 @@
2121
from twisted.internet.interfaces import IStreamClientEndpoint
2222
from typing_extensions import Self
2323

24+
from hathor.p2p.peer_id import PeerId
2425
from hathor.reactor import ReactorProtocol as Reactor
25-
from hathor.types import Hash
2626

2727

2828
class Protocol(Enum):
2929
TCP = 'tcp'
3030

3131

32-
class PeerId(Hash):
33-
pass
34-
35-
3632
@dataclass(frozen=True, slots=True)
3733
class Entrypoint:
3834
"""Endpoint description (returned from DNS query, or received from the p2p network) may contain a peer-id."""

hathor/p2p/manager.py

+15-14
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from hathor.p2p.netfilter.factory import NetfilterFactory
3030
from hathor.p2p.peer import Peer
3131
from hathor.p2p.peer_discovery import PeerDiscovery
32+
from hathor.p2p.peer_id import PeerId
3233
from hathor.p2p.peer_storage import PeerStorage
3334
from hathor.p2p.protocol import HathorProtocol
3435
from hathor.p2p.rate_limiter import RateLimiter
@@ -51,11 +52,11 @@
5152

5253

5354
class _SyncRotateInfo(NamedTuple):
54-
candidates: list[str]
55-
old: set[str]
56-
new: set[str]
57-
to_disable: set[str]
58-
to_enable: set[str]
55+
candidates: list[PeerId]
56+
old: set[PeerId]
57+
new: set[PeerId]
58+
to_disable: set[PeerId]
59+
to_enable: set[PeerId]
5960

6061

6162
class _ConnectingPeer(NamedTuple):
@@ -79,7 +80,7 @@ class GlobalRateLimiter:
7980

8081
manager: Optional['HathorManager']
8182
connections: set[HathorProtocol]
82-
connected_peers: dict[str, HathorProtocol]
83+
connected_peers: dict[PeerId, HathorProtocol]
8384
connecting_peers: dict[IStreamClientEndpoint, _ConnectingPeer]
8485
handshaking_peers: set[HathorProtocol]
8586
whitelist_only: bool
@@ -174,7 +175,7 @@ def __init__(
174175
self.lc_sync_update_interval: float = 5 # seconds
175176

176177
# Peers that always have sync enabled.
177-
self.always_enable_sync: set[str] = set()
178+
self.always_enable_sync: set[PeerId] = set()
178179

179180
# Timestamp of the last time sync was updated.
180181
self._last_sync_rotate: float = 0.
@@ -485,7 +486,7 @@ def iter_not_ready_endpoints(self) -> Iterable[Entrypoint]:
485486
else:
486487
self.log.warn('handshaking protocol has empty connection string', protocol=protocol)
487488

488-
def is_peer_connected(self, peer_id: str) -> bool:
489+
def is_peer_connected(self, peer_id: PeerId) -> bool:
489490
"""
490491
:type peer_id: string (peer.id)
491492
"""
@@ -729,7 +730,7 @@ def get_connection_to_drop(self, protocol: HathorProtocol) -> HathorProtocol:
729730
assert protocol.peer.id is not None
730731
assert protocol.my_peer.id is not None
731732
other_connection = self.connected_peers[protocol.peer.id]
732-
if protocol.my_peer.id > protocol.peer.id:
733+
if bytes(protocol.my_peer.id) > bytes(protocol.peer.id):
733734
# connection started by me is kept
734735
if not protocol.inbound:
735736
# other connection is dropped
@@ -751,7 +752,7 @@ def drop_connection(self, protocol: HathorProtocol) -> None:
751752
self.log.debug('dropping connection', peer_id=protocol.peer.id, protocol=type(protocol).__name__)
752753
protocol.send_error_and_close_connection('Connection droped')
753754

754-
def drop_connection_by_peer_id(self, peer_id: str) -> None:
755+
def drop_connection_by_peer_id(self, peer_id: PeerId) -> None:
755756
""" Drop a connection by peer id
756757
"""
757758
protocol = self.connected_peers.get(peer_id)
@@ -765,9 +766,9 @@ def sync_update(self) -> None:
765766
except Exception:
766767
self.log.error('_sync_rotate_if_needed failed', exc_info=True)
767768

768-
def set_always_enable_sync(self, values: list[str]) -> None:
769+
def set_always_enable_sync(self, values: list[PeerId]) -> None:
769770
"""Set a new list of peers to always enable sync. This operation completely replaces the previous list."""
770-
new: set[str] = set(values)
771+
new: set[PeerId] = set(values)
771772

772773
old = self.always_enable_sync
773774
if new == old:
@@ -792,14 +793,14 @@ def set_always_enable_sync(self, values: list[str]) -> None:
792793

793794
def _calculate_sync_rotate(self) -> _SyncRotateInfo:
794795
"""Calculate new sync rotation."""
795-
current_enabled: set[str] = set()
796+
current_enabled: set[PeerId] = set()
796797
for peer_id, conn in self.connected_peers.items():
797798
if conn.is_sync_enabled():
798799
current_enabled.add(peer_id)
799800

800801
candidates = list(self.connected_peers.keys())
801802
self.rng.shuffle(candidates)
802-
selected_peers: set[str] = set(candidates[:self.MAX_ENABLED_SYNC])
803+
selected_peers: set[PeerId] = set(candidates[:self.MAX_ENABLED_SYNC])
803804

804805
to_disable = current_enabled - selected_peers
805806
to_enable = selected_peers - current_enabled

hathor/p2p/netfilter/matches.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ def match(self, context: 'NetfilterContext') -> bool:
130130
if context.protocol.peer is None:
131131
return False
132132

133-
if context.protocol.peer.id != self.peer_id:
133+
if str(context.protocol.peer.id) != self.peer_id:
134134
return False
135135

136136
return True

hathor/p2p/peer.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
from hathor.conf.get_settings import get_global_settings
3333
from hathor.daa import DifficultyAdjustmentAlgorithm
3434
from hathor.p2p.entrypoint import Entrypoint
35+
from hathor.p2p.peer_id import PeerId
3536
from hathor.p2p.utils import discover_dns, generate_certificate
3637
from hathor.util import not_none
3738

@@ -59,7 +60,7 @@ class Peer:
5960
Usually a peer will have only one entrypoint.
6061
"""
6162

62-
id: Optional[str]
63+
id: Optional[PeerId]
6364
entrypoints: list[Entrypoint]
6465
private_key: Optional[rsa.RSAPrivateKeyWithSerialization]
6566
public_key: Optional[rsa.RSAPublicKey]
@@ -135,15 +136,15 @@ def generate_keys(self, key_size: int = 2048) -> None:
135136
self.public_key = self.private_key.public_key()
136137
self.id = self.calculate_id()
137138

138-
def calculate_id(self) -> str:
139+
def calculate_id(self) -> PeerId:
139140
""" Calculate and return the id based on the public key.
140141
"""
141142
assert self.public_key is not None
142143
public_der = self.public_key.public_bytes(encoding=serialization.Encoding.DER,
143144
format=serialization.PublicFormat.SubjectPublicKeyInfo)
144145
h1 = hashlib.sha256(public_der)
145146
h2 = hashlib.sha256(h1.digest())
146-
return h2.hexdigest()
147+
return PeerId(h2.digest())
147148

148149
def get_public_key(self) -> str:
149150
""" Return the public key in DER encoding as an `str`.
@@ -189,7 +190,7 @@ def create_from_json(cls, data: dict[str, Any]) -> 'Peer':
189190
from a peer connection.
190191
"""
191192
obj = cls(auto_generate_keys=False)
192-
obj.id = data['id']
193+
obj.id = PeerId(data['id'])
193194

194195
if 'pubKey' in data:
195196
public_key_der = base64.b64decode(data['pubKey'])
@@ -252,7 +253,7 @@ def to_json(self, include_private_key: bool = False) -> dict[str, Any]:
252253
format=serialization.PublicFormat.SubjectPublicKeyInfo)
253254
# This format is compatible with libp2p.
254255
result = {
255-
'id': self.id,
256+
'id': str(self.id),
256257
'pubKey': base64.b64encode(public_der).decode('utf-8'),
257258
'entrypoints': self.entrypoints_as_str(),
258259
}

hathor/p2p/peer_id.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Copyright 2024 Hathor Labs
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from hathor.types import Hash
16+
17+
18+
class PeerId(Hash):
19+
pass

hathor/p2p/peer_storage.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
# limitations under the License.
1414

1515
from hathor.p2p.peer import Peer
16+
from hathor.p2p.peer_id import PeerId
1617

1718

18-
class PeerStorage(dict[str, Peer]):
19+
class PeerStorage(dict[PeerId, Peer]):
1920
""" PeerStorage is used to store all known peers in memory.
2021
It is a dict of peer objects, and peers can be retrieved by their `peer.id`.
2122
"""

hathor/p2p/protocol.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from hathor.p2p.entrypoint import Entrypoint
2828
from hathor.p2p.messages import ProtocolMessages
2929
from hathor.p2p.peer import Peer
30+
from hathor.p2p.peer_id import PeerId
3031
from hathor.p2p.rate_limiter import RateLimiter
3132
from hathor.p2p.states import BaseState, HelloState, PeerIdState, ReadyState
3233
from hathor.p2p.sync_version import SyncVersion
@@ -192,7 +193,7 @@ def get_short_remote(self) -> str:
192193
assert self.transport is not None
193194
return format_address(self.transport.getPeer())
194195

195-
def get_peer_id(self) -> Optional[str]:
196+
def get_peer_id(self) -> Optional[PeerId]:
196197
"""Get peer id for logging."""
197198
if self.peer and self.peer.id:
198199
return self.peer.id
@@ -201,7 +202,7 @@ def get_peer_id(self) -> Optional[str]:
201202
def get_short_peer_id(self) -> Optional[str]:
202203
"""Get short peer id for logging."""
203204
if self.peer and self.peer.id:
204-
return self.peer.id[:7]
205+
return str(self.peer.id)[:7]
205206
return None
206207

207208
def get_logger_context(self) -> dict[str, Optional[str]]:

hathor/p2p/resources/status.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def render_GET(self, request):
6464
status = {}
6565
status[conn.state.sync_agent.name] = conn.state.sync_agent.get_status()
6666
connected_peers.append({
67-
'id': conn.peer.id,
67+
'id': str(conn.peer.id),
6868
'app_version': conn.app_version,
6969
'current_time': now,
7070
'uptime': now - conn.connection_time,
@@ -82,7 +82,7 @@ def render_GET(self, request):
8282
known_peers = []
8383
for peer in self.manager.connections.peer_storage.values():
8484
known_peers.append({
85-
'id': peer.id,
85+
'id': str(peer.id),
8686
'entrypoints': peer.entrypoints_as_str(),
8787
'last_seen': now - peer.last_seen,
8888
'flags': [flag.value for flag in peer.flags],
@@ -102,7 +102,7 @@ def render_GET(self, request):
102102

103103
data = {
104104
'server': {
105-
'id': self.manager.connections.my_peer.id,
105+
'id': str(self.manager.connections.my_peer.id),
106106
'app_version': app,
107107
'state': self.manager.state.value,
108108
'network': self.manager.network,

hathor/p2p/states/peer_id.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from hathor.conf.settings import HathorSettings
2020
from hathor.p2p.messages import ProtocolMessages
2121
from hathor.p2p.peer import Peer
22+
from hathor.p2p.peer_id import PeerId
2223
from hathor.p2p.states.base import BaseState
2324
from hathor.util import json_dumps, json_loads
2425

@@ -68,7 +69,7 @@ def send_peer_id(self) -> None:
6869
protocol = self.protocol
6970
my_peer = protocol.my_peer
7071
hello = {
71-
'id': my_peer.id,
72+
'id': str(my_peer.id),
7273
'pubKey': my_peer.get_public_key(),
7374
'entrypoints': my_peer.entrypoints_as_str(),
7475
}
@@ -139,7 +140,7 @@ async def handle_peer_id(self, payload: str) -> None:
139140

140141
self.send_ready()
141142

142-
def _should_block_peer(self, peer_id: str) -> bool:
143+
def _should_block_peer(self, peer_id: PeerId) -> bool:
143144
""" Determine if peer should not be allowed to connect.
144145
145146
Currently this is only because the peer is not in a whitelist and whitelist blocking is active.

0 commit comments

Comments
 (0)