astreum 0.3.16__py3-none-any.whl → 0.3.46__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astreum/__init__.py +1 -2
- astreum/communication/__init__.py +15 -11
- astreum/communication/difficulty.py +39 -0
- astreum/communication/disconnect.py +57 -0
- astreum/communication/handlers/handshake.py +105 -62
- astreum/communication/handlers/object_request.py +179 -149
- astreum/communication/handlers/object_response.py +7 -1
- astreum/communication/handlers/ping.py +9 -0
- astreum/communication/handlers/route_request.py +7 -1
- astreum/communication/handlers/route_response.py +7 -1
- astreum/communication/incoming_queue.py +96 -0
- astreum/communication/message_pow.py +36 -0
- astreum/communication/models/peer.py +4 -0
- astreum/communication/models/ping.py +27 -6
- astreum/communication/models/route.py +4 -0
- astreum/communication/{start.py → node.py} +10 -11
- astreum/communication/outgoing_queue.py +108 -0
- astreum/communication/processors/incoming.py +110 -37
- astreum/communication/processors/outgoing.py +35 -2
- astreum/communication/processors/peer.py +133 -58
- astreum/communication/setup.py +272 -113
- astreum/communication/util.py +14 -0
- astreum/node.py +99 -92
- astreum/storage/actions/get.py +79 -48
- astreum/storage/actions/set.py +171 -156
- astreum/storage/providers.py +24 -0
- astreum/storage/setup.py +23 -22
- astreum/utils/config.py +234 -45
- astreum/utils/logging.py +1 -1
- astreum/{consensus → validation}/__init__.py +0 -4
- astreum/validation/constants.py +2 -0
- astreum/{consensus → validation}/genesis.py +4 -6
- astreum/validation/models/block.py +544 -0
- astreum/validation/models/fork.py +511 -0
- astreum/{consensus → validation}/models/receipt.py +17 -4
- astreum/{consensus → validation}/models/transaction.py +45 -3
- astreum/validation/node.py +190 -0
- astreum/{consensus → validation}/validator.py +1 -1
- astreum/validation/workers/__init__.py +8 -0
- astreum/{consensus → validation}/workers/validation.py +360 -333
- astreum/verification/__init__.py +4 -0
- astreum/{consensus/workers/discovery.py → verification/discover.py} +1 -1
- astreum/verification/node.py +61 -0
- astreum/verification/worker.py +183 -0
- {astreum-0.3.16.dist-info → astreum-0.3.46.dist-info}/METADATA +43 -9
- astreum-0.3.46.dist-info/RECORD +79 -0
- astreum/consensus/models/block.py +0 -364
- astreum/consensus/models/chain.py +0 -66
- astreum/consensus/models/fork.py +0 -100
- astreum/consensus/setup.py +0 -83
- astreum/consensus/start.py +0 -67
- astreum/consensus/workers/__init__.py +0 -9
- astreum/consensus/workers/verify.py +0 -90
- astreum-0.3.16.dist-info/RECORD +0 -72
- /astreum/{consensus → validation}/models/__init__.py +0 -0
- /astreum/{consensus → validation}/models/account.py +0 -0
- /astreum/{consensus → validation}/models/accounts.py +0 -0
- {astreum-0.3.16.dist-info → astreum-0.3.46.dist-info}/WHEEL +0 -0
- {astreum-0.3.16.dist-info → astreum-0.3.46.dist-info}/licenses/LICENSE +0 -0
- {astreum-0.3.16.dist-info → astreum-0.3.46.dist-info}/top_level.txt +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from queue import Empty
|
|
3
4
|
from typing import TYPE_CHECKING, Tuple
|
|
4
5
|
|
|
5
6
|
if TYPE_CHECKING:
|
|
@@ -7,14 +8,46 @@ if TYPE_CHECKING:
|
|
|
7
8
|
|
|
8
9
|
def process_outgoing_messages(node: "Node") -> None:
|
|
9
10
|
"""Send queued outbound packets."""
|
|
10
|
-
|
|
11
|
+
stop = getattr(node, "communication_stop_event", None)
|
|
12
|
+
while stop is None or not stop.is_set():
|
|
11
13
|
try:
|
|
12
|
-
|
|
14
|
+
item = node.outgoing_queue.get(timeout=0.5)
|
|
15
|
+
except Empty:
|
|
16
|
+
continue
|
|
13
17
|
except Exception:
|
|
14
18
|
node.logger.exception("Error taking from outgoing queue")
|
|
15
19
|
continue
|
|
16
20
|
|
|
21
|
+
payload = None
|
|
22
|
+
addr = None
|
|
23
|
+
accounted_size = None
|
|
24
|
+
if isinstance(item, tuple) and len(item) == 3:
|
|
25
|
+
payload, addr, accounted_size = item
|
|
26
|
+
elif isinstance(item, tuple) and len(item) == 2:
|
|
27
|
+
payload, addr = item
|
|
28
|
+
else:
|
|
29
|
+
node.logger.warning("Outgoing queue item has unexpected shape: %r", item)
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
if stop is not None and stop.is_set():
|
|
33
|
+
if accounted_size is not None:
|
|
34
|
+
try:
|
|
35
|
+
with node.outgoing_queue_size_lock:
|
|
36
|
+
node.outgoing_queue_size = max(0, node.outgoing_queue_size - int(accounted_size))
|
|
37
|
+
except Exception:
|
|
38
|
+
node.logger.exception("Failed updating outgoing_queue_size on shutdown")
|
|
39
|
+
break
|
|
40
|
+
|
|
17
41
|
try:
|
|
18
42
|
node.outgoing_socket.sendto(payload, addr)
|
|
19
43
|
except Exception as exc:
|
|
20
44
|
node.logger.warning("Error sending message to %s: %s", addr, exc)
|
|
45
|
+
finally:
|
|
46
|
+
if accounted_size is not None:
|
|
47
|
+
try:
|
|
48
|
+
with node.outgoing_queue_size_lock:
|
|
49
|
+
node.outgoing_queue_size = max(0, node.outgoing_queue_size - int(accounted_size))
|
|
50
|
+
except Exception:
|
|
51
|
+
node.logger.exception("Failed updating outgoing_queue_size")
|
|
52
|
+
|
|
53
|
+
node.logger.info("Outgoing message processor stopped")
|
|
@@ -1,59 +1,134 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import time
|
|
4
|
-
from datetime import datetime, timedelta, timezone
|
|
5
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from datetime import datetime, timedelta, timezone
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from ..models.message import Message
|
|
8
|
+
from ..outgoing_queue import enqueue_outgoing
|
|
9
|
+
from ..util import address_str_to_host_and_port
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from .. import Node
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _queue_bootstrap_handshakes(node: "Node") -> int:
|
|
16
|
+
relay_public_key = node.relay_public_key
|
|
17
|
+
|
|
18
|
+
bootstrap_peers = node.bootstrap_peers
|
|
19
|
+
if not bootstrap_peers:
|
|
20
|
+
return 0
|
|
21
|
+
|
|
22
|
+
try:
|
|
23
|
+
incoming_port = int(node.config.get("incoming_port", 0))
|
|
24
|
+
content = incoming_port.to_bytes(2, "big", signed=False)
|
|
25
|
+
except (TypeError, ValueError, OverflowError):
|
|
26
|
+
return 0
|
|
27
|
+
|
|
28
|
+
handshake_message = Message(
|
|
29
|
+
handshake=True,
|
|
30
|
+
sender=relay_public_key,
|
|
31
|
+
content=content,
|
|
32
|
+
)
|
|
33
|
+
handshake_bytes = handshake_message.to_bytes()
|
|
34
|
+
sent = 0
|
|
35
|
+
for addr in bootstrap_peers:
|
|
36
|
+
try:
|
|
37
|
+
host, port = address_str_to_host_and_port(addr)
|
|
38
|
+
except Exception as exc:
|
|
39
|
+
node.logger.warning("Invalid bootstrap address %s: %s", addr, exc)
|
|
40
|
+
continue
|
|
21
41
|
try:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
42
|
+
queued = enqueue_outgoing(
|
|
43
|
+
node,
|
|
44
|
+
(host, port),
|
|
45
|
+
message_bytes=handshake_bytes,
|
|
46
|
+
difficulty=1,
|
|
47
|
+
)
|
|
48
|
+
except Exception as exc:
|
|
49
|
+
node.logger.debug(
|
|
50
|
+
"Failed queueing bootstrap handshake to %s:%s: %s",
|
|
51
|
+
host,
|
|
52
|
+
port,
|
|
53
|
+
exc,
|
|
54
|
+
)
|
|
55
|
+
continue
|
|
56
|
+
if queued:
|
|
57
|
+
node.logger.info("Retrying bootstrap handshake to %s:%s", host, port)
|
|
58
|
+
sent += 1
|
|
59
|
+
else:
|
|
60
|
+
node.logger.debug(
|
|
61
|
+
"Bootstrap handshake queue rejected for %s:%s",
|
|
62
|
+
host,
|
|
63
|
+
port,
|
|
64
|
+
)
|
|
65
|
+
return sent
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def manage_peer(node: "Node") -> None:
|
|
69
|
+
"""Continuously evict peers whose timestamps exceed the configured timeout."""
|
|
70
|
+
node.logger.info(
|
|
71
|
+
"Peer manager started (timeout=%3ds, interval=%3ds)",
|
|
72
|
+
node.config["peer_timeout"],
|
|
73
|
+
node.config["peer_timeout_interval"],
|
|
74
|
+
)
|
|
75
|
+
stop = getattr(node, "communication_stop_event", None)
|
|
76
|
+
while stop is None or not stop.is_set():
|
|
77
|
+
timeout_seconds = node.config["peer_timeout"]
|
|
78
|
+
interval_seconds = node.config["peer_timeout_interval"]
|
|
79
|
+
try:
|
|
80
|
+
peers = getattr(node, "peers", None)
|
|
81
|
+
peer_route = getattr(node, "peer_route", None)
|
|
82
|
+
if not isinstance(peers, dict) or peer_route is None:
|
|
83
|
+
time.sleep(interval_seconds)
|
|
84
|
+
continue
|
|
85
|
+
|
|
86
|
+
cutoff = datetime.now(timezone.utc) - timedelta(seconds=timeout_seconds)
|
|
87
|
+
stale_keys = []
|
|
88
|
+
with node.peers_lock:
|
|
89
|
+
for peer_key, peer in list(peers.items()):
|
|
90
|
+
if peer.timestamp < cutoff:
|
|
91
|
+
stale_keys.append(peer_key)
|
|
92
|
+
|
|
93
|
+
removed_count = 0
|
|
94
|
+
for peer_key in stale_keys:
|
|
95
|
+
removed = node.remove_peer(peer_key)
|
|
96
|
+
if removed is None:
|
|
97
|
+
continue
|
|
98
|
+
removed_count += 1
|
|
99
|
+
try:
|
|
100
|
+
peer_route.remove_peer(peer_key)
|
|
101
|
+
except Exception:
|
|
102
|
+
node.logger.debug(
|
|
103
|
+
"Unable to remove peer %s from route",
|
|
104
|
+
peer_key.hex(),
|
|
105
|
+
)
|
|
106
|
+
node.logger.debug(
|
|
107
|
+
"Evicted stale peer %s last seen at %s",
|
|
108
|
+
peer_key.hex(),
|
|
109
|
+
getattr(removed, "timestamp", None),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if removed_count:
|
|
113
|
+
node.logger.info("Peer manager removed %s stale peer(s)", removed_count)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
with node.peers_lock:
|
|
117
|
+
peer_count = len(peers)
|
|
118
|
+
except Exception:
|
|
119
|
+
peer_count = len(getattr(node, "peers", {}) or {})
|
|
120
|
+
if peer_count == 0:
|
|
121
|
+
bootstrap_interval = node.config.get("bootstrap_retry_interval", 0)
|
|
122
|
+
now = time.time()
|
|
123
|
+
last_attempt = getattr(node, "_bootstrap_last_attempt", 0.0)
|
|
124
|
+
if bootstrap_interval and (now - last_attempt) >= bootstrap_interval:
|
|
125
|
+
sent = _queue_bootstrap_handshakes(node)
|
|
126
|
+
if sent:
|
|
127
|
+
node._bootstrap_last_attempt = now
|
|
128
|
+
except Exception:
|
|
129
|
+
node.logger.exception("Peer manager iteration failed")
|
|
130
|
+
|
|
131
|
+
if stop is not None and stop.wait(interval_seconds):
|
|
132
|
+
break
|
|
133
|
+
|
|
134
|
+
node.logger.info("Peer manager stopped")
|