astreum 0.3.9__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 +5 -4
- astreum/communication/__init__.py +15 -11
- astreum/communication/difficulty.py +39 -0
- astreum/communication/disconnect.py +57 -0
- astreum/communication/handlers/handshake.py +105 -89
- 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 +134 -0
- astreum/communication/setup.py +273 -112
- astreum/communication/util.py +14 -0
- astreum/node.py +99 -89
- 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 +247 -30
- 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 +18 -9
- astreum/validation/workers/__init__.py +8 -0
- astreum/{consensus → validation}/workers/validation.py +361 -307
- 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.9.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.9.dist-info/RECORD +0 -71
- /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.9.dist-info → astreum-0.3.46.dist-info}/WHEEL +0 -0
- {astreum-0.3.9.dist-info → astreum-0.3.46.dist-info}/licenses/LICENSE +0 -0
- {astreum-0.3.9.dist-info → astreum-0.3.46.dist-info}/top_level.txt +0 -0
astreum/__init__.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
from astreum.
|
|
3
|
-
from astreum.machine import Env, Expr
|
|
1
|
+
|
|
2
|
+
from astreum.validation import Account, Accounts, Block, Fork, Receipt, Transaction
|
|
3
|
+
from astreum.machine import Env, Expr, parse, tokenize
|
|
4
4
|
from astreum.node import Node
|
|
5
5
|
|
|
6
6
|
|
|
@@ -9,10 +9,11 @@ __all__: list[str] = [
|
|
|
9
9
|
"Env",
|
|
10
10
|
"Expr",
|
|
11
11
|
"Block",
|
|
12
|
-
"Chain",
|
|
13
12
|
"Fork",
|
|
14
13
|
"Receipt",
|
|
15
14
|
"Transaction",
|
|
16
15
|
"Account",
|
|
17
16
|
"Accounts",
|
|
17
|
+
"parse",
|
|
18
|
+
"tokenize",
|
|
18
19
|
]
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
from .models.message import Message
|
|
2
|
-
from .models.peer import Peer
|
|
3
|
-
from .models.route import Route
|
|
4
|
-
from .
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
|
|
1
|
+
from .models.message import Message
|
|
2
|
+
from .models.peer import Peer
|
|
3
|
+
from .models.route import Route
|
|
4
|
+
from .incoming_queue import enqueue_incoming
|
|
5
|
+
from .outgoing_queue import enqueue_outgoing
|
|
6
|
+
from .setup import communication_setup
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Message",
|
|
10
|
+
"Peer",
|
|
11
|
+
"Route",
|
|
12
|
+
"enqueue_incoming",
|
|
13
|
+
"enqueue_outgoing",
|
|
14
|
+
"communication_setup",
|
|
15
|
+
]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .. import Node
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def message_difficulty(node: "Node") -> int:
|
|
10
|
+
"""Compute current message difficulty based on incoming queue pressure."""
|
|
11
|
+
size = node.incoming_queue_size
|
|
12
|
+
limit = node.incoming_queue_size_limit
|
|
13
|
+
|
|
14
|
+
if limit <= 0:
|
|
15
|
+
return 1
|
|
16
|
+
|
|
17
|
+
pressure = size / limit
|
|
18
|
+
if pressure < 0.70:
|
|
19
|
+
value = 1
|
|
20
|
+
elif pressure < 0.75:
|
|
21
|
+
value = 3
|
|
22
|
+
elif pressure < 0.80:
|
|
23
|
+
value = 5
|
|
24
|
+
elif pressure < 0.85:
|
|
25
|
+
value = 8
|
|
26
|
+
elif pressure < 0.90:
|
|
27
|
+
value = 12
|
|
28
|
+
elif pressure < 0.93:
|
|
29
|
+
value = 16
|
|
30
|
+
elif pressure < 0.95:
|
|
31
|
+
value = 19
|
|
32
|
+
elif pressure < 0.97:
|
|
33
|
+
value = 22
|
|
34
|
+
elif pressure < 0.98:
|
|
35
|
+
value = 24
|
|
36
|
+
else:
|
|
37
|
+
value = 26
|
|
38
|
+
|
|
39
|
+
return max(1, min(255, value))
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""Helpers related to disconnecting communication components."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from astreum.node import Node
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
_SOCKET_ATTRS: tuple[str, ...] = ("incoming_socket", "outgoing_socket")
|
|
12
|
+
_THREAD_ATTRS: tuple[str, ...] = (
|
|
13
|
+
"incoming_populate_thread",
|
|
14
|
+
"incoming_process_thread",
|
|
15
|
+
"outgoing_thread",
|
|
16
|
+
"peer_manager_thread",
|
|
17
|
+
"latest_block_discovery_thread",
|
|
18
|
+
"verify_thread",
|
|
19
|
+
"consensus_validation_thread",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _set_event(node: "Node", attr_name: str) -> None:
|
|
24
|
+
event = getattr(node, attr_name, None)
|
|
25
|
+
if event is not None:
|
|
26
|
+
event.set()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _close_socket(node: "Node", attr_name: str) -> None:
|
|
30
|
+
sock = getattr(node, attr_name, None)
|
|
31
|
+
if sock is None:
|
|
32
|
+
return
|
|
33
|
+
try:
|
|
34
|
+
sock.close()
|
|
35
|
+
except Exception as exc: # pragma: no cover - defensive logging path
|
|
36
|
+
node.logger.warning("Error closing %s: %s", attr_name, exc)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def disconnect_node(node: "Node") -> None:
|
|
40
|
+
"""Gracefully stop worker threads and close communication sockets."""
|
|
41
|
+
node.logger.info("Disconnecting Astreum Node")
|
|
42
|
+
|
|
43
|
+
_set_event(node, "communication_stop_event")
|
|
44
|
+
_set_event(node, "_validation_stop_event")
|
|
45
|
+
_set_event(node, "_verify_stop_event")
|
|
46
|
+
|
|
47
|
+
for sock_name in _SOCKET_ATTRS:
|
|
48
|
+
_close_socket(node, sock_name)
|
|
49
|
+
|
|
50
|
+
for thread_name in _THREAD_ATTRS:
|
|
51
|
+
thread = getattr(node, thread_name, None)
|
|
52
|
+
if thread is None or not thread.is_alive():
|
|
53
|
+
continue
|
|
54
|
+
thread.join(timeout=1.0)
|
|
55
|
+
|
|
56
|
+
node.is_connected = False
|
|
57
|
+
node.logger.info("Node disconnected")
|
|
@@ -1,89 +1,105 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import TYPE_CHECKING, Sequence
|
|
4
|
-
|
|
5
|
-
from cryptography.hazmat.primitives import serialization
|
|
6
|
-
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PublicKey
|
|
7
|
-
|
|
8
|
-
from ..
|
|
9
|
-
from ..models.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Sequence
|
|
4
|
+
|
|
5
|
+
from cryptography.hazmat.primitives import serialization
|
|
6
|
+
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PublicKey
|
|
7
|
+
|
|
8
|
+
from ..outgoing_queue import enqueue_outgoing
|
|
9
|
+
from ..models.peer import Peer
|
|
10
|
+
from ..models.message import Message, MessageTopic
|
|
11
|
+
from ..models.ping import Ping
|
|
12
|
+
from ..difficulty import message_difficulty
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .... import Node
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def handle_handshake(node: "Node", addr: Sequence[object], message: Message) -> bool:
|
|
19
|
+
"""Handle incoming handshake messages.
|
|
20
|
+
|
|
21
|
+
Returns True if the outer loop should `continue`, False otherwise.
|
|
22
|
+
"""
|
|
23
|
+
def _queue_handshake_ping(peer: Peer, peer_address: tuple[str, int]) -> None:
|
|
24
|
+
latest_block = getattr(node, "latest_block_hash", None)
|
|
25
|
+
if not isinstance(latest_block, (bytes, bytearray)) or len(latest_block) != 32:
|
|
26
|
+
latest_block = None
|
|
27
|
+
try:
|
|
28
|
+
ping_payload = Ping(
|
|
29
|
+
is_validator=bool(getattr(node, "validation_public_key", None)),
|
|
30
|
+
difficulty=message_difficulty(node),
|
|
31
|
+
latest_block=latest_block,
|
|
32
|
+
).to_bytes()
|
|
33
|
+
ping_msg = Message(
|
|
34
|
+
topic=MessageTopic.PING,
|
|
35
|
+
content=ping_payload,
|
|
36
|
+
sender=node.relay_public_key,
|
|
37
|
+
)
|
|
38
|
+
ping_msg.encrypt(peer.shared_key_bytes)
|
|
39
|
+
enqueue_outgoing(
|
|
40
|
+
node,
|
|
41
|
+
peer_address,
|
|
42
|
+
message=ping_msg,
|
|
43
|
+
difficulty=peer.difficulty,
|
|
44
|
+
)
|
|
45
|
+
except Exception as exc:
|
|
46
|
+
node.logger.debug(
|
|
47
|
+
"Failed sending handshake ping to %s:%s: %s",
|
|
48
|
+
peer_address[0],
|
|
49
|
+
peer_address[1],
|
|
50
|
+
exc,
|
|
51
|
+
)
|
|
52
|
+
sender_public_key_bytes = message.sender_bytes
|
|
53
|
+
try:
|
|
54
|
+
sender_key = X25519PublicKey.from_public_bytes(sender_public_key_bytes)
|
|
55
|
+
except Exception as exc:
|
|
56
|
+
node.logger.warning("Error extracting sender key bytes: %s", exc)
|
|
57
|
+
return True
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
host = addr[0]
|
|
61
|
+
port = int.from_bytes(message.content[:2], "big", signed=False)
|
|
62
|
+
except Exception:
|
|
63
|
+
return True
|
|
64
|
+
peer_address = (host, port)
|
|
65
|
+
default_seed_ips = getattr(node, "default_seed_ips", None)
|
|
66
|
+
is_default_seed = bool(default_seed_ips) and host in default_seed_ips
|
|
67
|
+
|
|
68
|
+
existing_peer = node.get_peer(sender_public_key_bytes)
|
|
69
|
+
if existing_peer is not None:
|
|
70
|
+
existing_peer.address = peer_address
|
|
71
|
+
existing_peer.is_default_seed = is_default_seed
|
|
72
|
+
_queue_handshake_ping(existing_peer, peer_address)
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
peer = Peer(
|
|
77
|
+
node_secret_key=node.relay_secret_key,
|
|
78
|
+
peer_public_key=sender_key,
|
|
79
|
+
address=peer_address,
|
|
80
|
+
is_default_seed=is_default_seed,
|
|
81
|
+
)
|
|
82
|
+
except Exception:
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
node.add_peer(sender_public_key_bytes, peer)
|
|
86
|
+
node.peer_route.add_peer(sender_public_key_bytes, peer)
|
|
87
|
+
|
|
88
|
+
node.logger.info(
|
|
89
|
+
"Handshake accepted from %s:%s; peer added",
|
|
90
|
+
peer_address[0],
|
|
91
|
+
peer_address[1],
|
|
92
|
+
)
|
|
93
|
+
response = Message(
|
|
94
|
+
handshake=True,
|
|
95
|
+
sender=node.relay_public_key,
|
|
96
|
+
content=int(node.config["incoming_port"]).to_bytes(2, "big", signed=False),
|
|
97
|
+
)
|
|
98
|
+
enqueue_outgoing(
|
|
99
|
+
node,
|
|
100
|
+
peer_address,
|
|
101
|
+
message=response,
|
|
102
|
+
difficulty=peer.difficulty,
|
|
103
|
+
)
|
|
104
|
+
_queue_handshake_ping(peer, peer_address)
|
|
105
|
+
return True
|