astreum 0.1.13__py3-none-any.whl → 0.1.15__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.
Potentially problematic release.
This version of astreum might be problematic. Click here for more details.
- astreum/lispeum/storage.py +10 -10
- astreum/lispeum/utils.py +17 -0
- astreum/node/__init__.py +358 -470
- astreum/node/relay/__init__.py +72 -30
- astreum/node/relay/envelope.py +5 -5
- astreum/node/storage/__init__.py +13 -0
- astreum/node/storage/merkle.py +734 -0
- astreum/node/{models.py → storage/storage.py} +41 -99
- astreum/node/storage/trie.py +146 -0
- astreum/node/storage/utils.py +137 -0
- astreum/node/utils.py +34 -0
- astreum/node/validation/__init__.py +84 -0
- astreum/node/validation/account.py +874 -0
- astreum/node/validation/block/__init__.py +12 -0
- astreum/node/validation/block/create.py +98 -0
- astreum/node/validation/block/model.py +81 -0
- astreum/node/validation/block/validate.py +196 -0
- astreum/node/validation/constants.py +15 -0
- astreum/node/validation/stake.py +229 -0
- astreum/node/validation/state.py +230 -0
- astreum/node/validation/vdf.py +80 -0
- {astreum-0.1.13.dist-info → astreum-0.1.15.dist-info}/METADATA +2 -1
- {astreum-0.1.13.dist-info → astreum-0.1.15.dist-info}/RECORD +26 -10
- {astreum-0.1.13.dist-info → astreum-0.1.15.dist-info}/LICENSE +0 -0
- {astreum-0.1.13.dist-info → astreum-0.1.15.dist-info}/WHEEL +0 -0
- {astreum-0.1.13.dist-info → astreum-0.1.15.dist-info}/top_level.txt +0 -0
astreum/node/relay/__init__.py
CHANGED
|
@@ -4,6 +4,8 @@ Relay module for handling network communication in the Astreum node.
|
|
|
4
4
|
|
|
5
5
|
import socket
|
|
6
6
|
import threading
|
|
7
|
+
import random
|
|
8
|
+
import time
|
|
7
9
|
from queue import Queue
|
|
8
10
|
from typing import Tuple, Callable, Dict, Set, Optional, List
|
|
9
11
|
from .message import Message, Topic
|
|
@@ -43,14 +45,16 @@ class Relay:
|
|
|
43
45
|
# Save private key bytes for config persistence
|
|
44
46
|
self.private_key_bytes = self.private_key.private_bytes_raw()
|
|
45
47
|
|
|
46
|
-
# Routes that this node participates in
|
|
48
|
+
# Routes that this node participates in
|
|
49
|
+
# 0 = peer route, 1 = validation route
|
|
50
|
+
# All routes are tracked by default, but we only join some
|
|
47
51
|
self.routes: List[int] = []
|
|
52
|
+
self.tracked_routes: List[int] = [0, 1] # Track all routes
|
|
48
53
|
|
|
49
|
-
#
|
|
54
|
+
# Always join peer route
|
|
50
55
|
self.routes.append(0) # Peer route
|
|
51
56
|
|
|
52
|
-
# Check if
|
|
53
|
-
# This is now controlled by the parent Node class based on validation_private_key
|
|
57
|
+
# Check if this node should join validation route
|
|
54
58
|
if config.get('validation_route', False):
|
|
55
59
|
self.routes.append(1) # Validation route
|
|
56
60
|
|
|
@@ -102,24 +106,53 @@ class Relay:
|
|
|
102
106
|
def is_in_validation_route(self) -> bool:
|
|
103
107
|
"""Check if this node is part of the validation route."""
|
|
104
108
|
return 1 in self.routes
|
|
109
|
+
|
|
110
|
+
def is_tracking_route(self, route_type: int) -> bool:
|
|
111
|
+
"""Check if this node is tracking a specific route."""
|
|
112
|
+
return route_type in self.tracked_routes
|
|
105
113
|
|
|
106
|
-
def
|
|
114
|
+
def get_random_peers_from_route(self, route_type: int, count: int = 3) -> List[Peer]:
|
|
107
115
|
"""
|
|
108
|
-
|
|
116
|
+
Get a list of random peers from different buckets in the specified route.
|
|
109
117
|
|
|
110
118
|
Args:
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
route_type (int): Route type (0 for peer, 1 for validation)
|
|
120
|
+
count (int): Number of random peers to select (one from each bucket)
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
List[Peer]: List of randomly selected peers from different buckets
|
|
113
124
|
"""
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
125
|
+
result = []
|
|
126
|
+
route_id = self._get_route_id(route_type)
|
|
127
|
+
|
|
128
|
+
# Get all buckets that have peers for this route
|
|
129
|
+
buckets_with_peers = []
|
|
130
|
+
for i, bucket in enumerate(self.routing_table):
|
|
131
|
+
# For each bucket, collect peers that are in this route
|
|
132
|
+
route_peers_in_bucket = [peer for peer in bucket.values()
|
|
133
|
+
if peer.routes and route_id in peer.routes]
|
|
134
|
+
if route_peers_in_bucket:
|
|
135
|
+
buckets_with_peers.append((i, route_peers_in_bucket))
|
|
136
|
+
|
|
137
|
+
# If we don't have any buckets with peers, return empty list
|
|
138
|
+
if not buckets_with_peers:
|
|
139
|
+
return []
|
|
140
|
+
|
|
141
|
+
# If we have fewer buckets than requested count, adjust count
|
|
142
|
+
sample_count = min(count, len(buckets_with_peers))
|
|
143
|
+
|
|
144
|
+
# Sample random buckets
|
|
145
|
+
selected_buckets = random.sample(buckets_with_peers, sample_count)
|
|
146
|
+
|
|
147
|
+
# For each selected bucket, pick one random peer
|
|
148
|
+
for bucket_idx, peers in selected_buckets:
|
|
149
|
+
# Select one random peer from this bucket
|
|
150
|
+
selected_peer = random.choice(peers)
|
|
151
|
+
result.append(selected_peer)
|
|
121
152
|
|
|
122
|
-
|
|
153
|
+
return result
|
|
154
|
+
|
|
155
|
+
def get_peers_in_route(self, route_type: int) -> List[Peer]:
|
|
123
156
|
"""
|
|
124
157
|
Get all peers in a specific route.
|
|
125
158
|
|
|
@@ -135,6 +168,22 @@ class Relay:
|
|
|
135
168
|
return self.validation_route_bucket.get_peers()
|
|
136
169
|
return []
|
|
137
170
|
|
|
171
|
+
def add_peer_to_route(self, peer: Peer, route_types: List[int]):
|
|
172
|
+
"""
|
|
173
|
+
Add a peer to specified routes.
|
|
174
|
+
|
|
175
|
+
Args:
|
|
176
|
+
peer (Peer): The peer to add
|
|
177
|
+
route_types (List[int]): List of route types to add the peer to (0 = peer, 1 = validation)
|
|
178
|
+
"""
|
|
179
|
+
for route_type in route_types:
|
|
180
|
+
if route_type == 0: # Peer route
|
|
181
|
+
# Add to top of bucket, eject last if at capacity
|
|
182
|
+
self.peer_route_bucket.add(peer, to_front=True)
|
|
183
|
+
elif route_type == 1: # Validation route
|
|
184
|
+
# Add to top of bucket, eject last if at capacity
|
|
185
|
+
self.validation_route_bucket.add(peer, to_front=True)
|
|
186
|
+
|
|
138
187
|
def register_message_handler(self, topic: Topic, handler_func):
|
|
139
188
|
"""Register a handler function for a specific message topic."""
|
|
140
189
|
self.message_handlers[topic] = handler_func
|
|
@@ -197,26 +246,19 @@ class Relay:
|
|
|
197
246
|
"""Handle an incoming message."""
|
|
198
247
|
envelope = Envelope.from_bytes(data)
|
|
199
248
|
if envelope and envelope.message.topic in self.message_handlers:
|
|
200
|
-
#
|
|
201
|
-
if envelope.message.topic
|
|
202
|
-
# Only process if we're part of the validation route
|
|
249
|
+
# For transaction messages, only process if we're in validation route
|
|
250
|
+
if envelope.message.topic == Topic.TRANSACTION:
|
|
203
251
|
if self.is_in_validation_route():
|
|
204
252
|
self.message_handlers[envelope.message.topic](envelope.message.body, addr, envelope)
|
|
205
|
-
|
|
206
|
-
|
|
253
|
+
# For block messages, only process if we're in validation route
|
|
254
|
+
elif envelope.message.topic == Topic.BLOCK:
|
|
207
255
|
if self.is_in_validation_route():
|
|
208
256
|
self.message_handlers[envelope.message.topic](envelope.message.body, addr, envelope)
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
self.message_handlers[envelope.message.topic](envelope.message.body, addr, envelope)
|
|
212
|
-
elif envelope.message.topic == Topic.OBJECT_REQUEST:
|
|
213
|
-
# Handle object request
|
|
214
|
-
self.message_handlers[envelope.message.topic](envelope.message.body, addr, envelope)
|
|
215
|
-
elif envelope.message.topic == Topic.OBJECT_RESPONSE:
|
|
216
|
-
# Handle object response
|
|
257
|
+
# Latest block and latest block requests can be handled by any node tracking the routes
|
|
258
|
+
elif envelope.message.topic in (Topic.LATEST_BLOCK, Topic.LATEST_BLOCK_REQUEST):
|
|
217
259
|
self.message_handlers[envelope.message.topic](envelope.message.body, addr, envelope)
|
|
260
|
+
# For other message types, always process
|
|
218
261
|
else:
|
|
219
|
-
# For other message types, always process
|
|
220
262
|
self.message_handlers[envelope.message.topic](envelope.message.body, addr, envelope)
|
|
221
263
|
|
|
222
264
|
def send(self, data: bytes, addr: Tuple[str, int]):
|
astreum/node/relay/envelope.py
CHANGED
|
@@ -31,11 +31,11 @@ determined by the difficulty parameter. The nonce is adjusted until this require
|
|
|
31
31
|
import struct
|
|
32
32
|
import time
|
|
33
33
|
import os
|
|
34
|
-
import hashlib
|
|
35
34
|
from dataclasses import dataclass
|
|
36
35
|
from typing import Optional, Tuple, List
|
|
37
36
|
from .message import Message, Topic
|
|
38
37
|
from astreum.utils.bytes_format import encode, decode
|
|
38
|
+
from ..utils import hash_data
|
|
39
39
|
|
|
40
40
|
@dataclass
|
|
41
41
|
class Envelope:
|
|
@@ -153,13 +153,13 @@ class Envelope:
|
|
|
153
153
|
bytes: The Merkle root hash
|
|
154
154
|
"""
|
|
155
155
|
if not leaves:
|
|
156
|
-
return
|
|
156
|
+
return hash_data(b'')
|
|
157
157
|
|
|
158
158
|
if len(leaves) == 1:
|
|
159
|
-
return
|
|
159
|
+
return hash_data(leaves[0])
|
|
160
160
|
|
|
161
161
|
# Hash all leaf nodes
|
|
162
|
-
hashed_leaves = [
|
|
162
|
+
hashed_leaves = [hash_data(leaf) for leaf in leaves]
|
|
163
163
|
|
|
164
164
|
# Build the Merkle tree
|
|
165
165
|
while len(hashed_leaves) > 1:
|
|
@@ -171,7 +171,7 @@ class Envelope:
|
|
|
171
171
|
next_level = []
|
|
172
172
|
for i in range(0, len(hashed_leaves), 2):
|
|
173
173
|
combined = hashed_leaves[i] + hashed_leaves[i+1]
|
|
174
|
-
next_level.append(
|
|
174
|
+
next_level.append(hash_data(combined))
|
|
175
175
|
|
|
176
176
|
hashed_leaves = next_level
|
|
177
177
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Storage utilities for the Astreum node.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .merkle import MerkleTree, MerkleProof, MerkleNode
|
|
6
|
+
from .merkle import find_first, find_all, map, binary_search
|
|
7
|
+
from .storage import Storage
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"MerkleTree", "MerkleProof", "MerkleNode",
|
|
11
|
+
"find_first", "find_all", "map", "binary_search",
|
|
12
|
+
"Storage"
|
|
13
|
+
]
|