nexaroa 0.0.111__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.
Files changed (78) hide show
  1. neuroshard/__init__.py +93 -0
  2. neuroshard/__main__.py +4 -0
  3. neuroshard/cli.py +466 -0
  4. neuroshard/core/__init__.py +92 -0
  5. neuroshard/core/consensus/verifier.py +252 -0
  6. neuroshard/core/crypto/__init__.py +20 -0
  7. neuroshard/core/crypto/ecdsa.py +392 -0
  8. neuroshard/core/economics/__init__.py +52 -0
  9. neuroshard/core/economics/constants.py +387 -0
  10. neuroshard/core/economics/ledger.py +2111 -0
  11. neuroshard/core/economics/market.py +975 -0
  12. neuroshard/core/economics/wallet.py +168 -0
  13. neuroshard/core/governance/__init__.py +74 -0
  14. neuroshard/core/governance/proposal.py +561 -0
  15. neuroshard/core/governance/registry.py +545 -0
  16. neuroshard/core/governance/versioning.py +332 -0
  17. neuroshard/core/governance/voting.py +453 -0
  18. neuroshard/core/model/__init__.py +30 -0
  19. neuroshard/core/model/dynamic.py +4186 -0
  20. neuroshard/core/model/llm.py +905 -0
  21. neuroshard/core/model/registry.py +164 -0
  22. neuroshard/core/model/scaler.py +387 -0
  23. neuroshard/core/model/tokenizer.py +568 -0
  24. neuroshard/core/network/__init__.py +56 -0
  25. neuroshard/core/network/connection_pool.py +72 -0
  26. neuroshard/core/network/dht.py +130 -0
  27. neuroshard/core/network/dht_plan.py +55 -0
  28. neuroshard/core/network/dht_proof_store.py +516 -0
  29. neuroshard/core/network/dht_protocol.py +261 -0
  30. neuroshard/core/network/dht_service.py +506 -0
  31. neuroshard/core/network/encrypted_channel.py +141 -0
  32. neuroshard/core/network/nat.py +201 -0
  33. neuroshard/core/network/nat_traversal.py +695 -0
  34. neuroshard/core/network/p2p.py +929 -0
  35. neuroshard/core/network/p2p_data.py +150 -0
  36. neuroshard/core/swarm/__init__.py +106 -0
  37. neuroshard/core/swarm/aggregation.py +729 -0
  38. neuroshard/core/swarm/buffers.py +643 -0
  39. neuroshard/core/swarm/checkpoint.py +709 -0
  40. neuroshard/core/swarm/compute.py +624 -0
  41. neuroshard/core/swarm/diloco.py +844 -0
  42. neuroshard/core/swarm/factory.py +1288 -0
  43. neuroshard/core/swarm/heartbeat.py +669 -0
  44. neuroshard/core/swarm/logger.py +487 -0
  45. neuroshard/core/swarm/router.py +658 -0
  46. neuroshard/core/swarm/service.py +640 -0
  47. neuroshard/core/training/__init__.py +29 -0
  48. neuroshard/core/training/checkpoint.py +600 -0
  49. neuroshard/core/training/distributed.py +1602 -0
  50. neuroshard/core/training/global_tracker.py +617 -0
  51. neuroshard/core/training/production.py +276 -0
  52. neuroshard/governance_cli.py +729 -0
  53. neuroshard/grpc_server.py +895 -0
  54. neuroshard/runner.py +3223 -0
  55. neuroshard/sdk/__init__.py +92 -0
  56. neuroshard/sdk/client.py +990 -0
  57. neuroshard/sdk/errors.py +101 -0
  58. neuroshard/sdk/types.py +282 -0
  59. neuroshard/tracker/__init__.py +0 -0
  60. neuroshard/tracker/server.py +864 -0
  61. neuroshard/ui/__init__.py +0 -0
  62. neuroshard/ui/app.py +102 -0
  63. neuroshard/ui/templates/index.html +1052 -0
  64. neuroshard/utils/__init__.py +0 -0
  65. neuroshard/utils/autostart.py +81 -0
  66. neuroshard/utils/hardware.py +121 -0
  67. neuroshard/utils/serialization.py +90 -0
  68. neuroshard/version.py +1 -0
  69. nexaroa-0.0.111.dist-info/METADATA +283 -0
  70. nexaroa-0.0.111.dist-info/RECORD +78 -0
  71. nexaroa-0.0.111.dist-info/WHEEL +5 -0
  72. nexaroa-0.0.111.dist-info/entry_points.txt +4 -0
  73. nexaroa-0.0.111.dist-info/licenses/LICENSE +190 -0
  74. nexaroa-0.0.111.dist-info/top_level.txt +2 -0
  75. protos/__init__.py +0 -0
  76. protos/neuroshard.proto +651 -0
  77. protos/neuroshard_pb2.py +160 -0
  78. protos/neuroshard_pb2_grpc.py +1298 -0
@@ -0,0 +1,261 @@
1
+ import grpc
2
+ import threading
3
+ import time
4
+ import logging
5
+ from concurrent import futures
6
+ from typing import List, Optional
7
+
8
+ from protos import neuroshard_pb2
9
+ from protos import neuroshard_pb2_grpc
10
+ from neuroshard.core.network.dht import Node, RoutingTable, ID_BITS
11
+ from neuroshard.core.network.dht_service import node_to_proto, proto_to_node
12
+ from neuroshard.core.network.connection_pool import get_channel
13
+
14
+ logger = logging.getLogger("DHT")
15
+
16
+ class DHTProtocol:
17
+ def __init__(self, local_node: Node, routing_table: RoutingTable, port: int):
18
+ self.local_node = local_node
19
+ self.routing_table = routing_table
20
+ self.port = port
21
+ # Initialize internal storage for DHT values (acting as a node)
22
+ self.storage = {}
23
+ # We don't manage the server here anymore, it's mixed into the main gRPC server
24
+ # Rate limiting for "no peers" messages (log max once per 60 seconds)
25
+ self._last_no_peers_log = {}
26
+
27
+ def _get_stub(self, target: Node):
28
+ # gRPC port assumption: http port + 1000
29
+ # If target.port is already the gRPC port, we use it directly.
30
+ # Our convention in p2p.py was: p_port = parsed.port or 80.
31
+ # And in grpc_server.py: grpc_port = port + 1000.
32
+ # So the node.port stored in DHT is likely the HTTP port.
33
+
34
+ # Let's assume Node stores HTTP port, so we add 1000.
35
+ # We should standardize this. For now, consistent with existing logic.
36
+ target_addr = f"{target.ip}:{target.port + 1000}"
37
+ channel = get_channel(target_addr)
38
+ return neuroshard_pb2_grpc.NeuroShardServiceStub(channel)
39
+
40
+ def ping(self, target: Node) -> bool:
41
+ """Send PING to target node."""
42
+ try:
43
+ stub = self._get_stub(target)
44
+ req = neuroshard_pb2.DHTPingRequest(
45
+ sender=node_to_proto(self.local_node)
46
+ )
47
+ resp = stub.DHTPing(req, timeout=2.0)
48
+ # Update routing table with responder
49
+ self.routing_table.add_contact(proto_to_node(resp.responder))
50
+ return True
51
+ except grpc.RpcError as e:
52
+ logger.debug(f"Ping failed to {target}: {e}")
53
+ return False
54
+
55
+ def find_node(self, target: Node, search_id: int) -> List[Node]:
56
+ """Ask target for nodes closest to search_id."""
57
+ try:
58
+ stub = self._get_stub(target)
59
+ req = neuroshard_pb2.DHTFindNodeRequest(
60
+ sender=node_to_proto(self.local_node),
61
+ target_id=search_id.to_bytes(20, byteorder='big')
62
+ )
63
+ resp = stub.DHTFindNode(req, timeout=5.0)
64
+
65
+ self.routing_table.add_contact(proto_to_node(resp.responder))
66
+
67
+ nodes = [proto_to_node(n) for n in resp.nodes]
68
+ return nodes
69
+ except grpc.RpcError:
70
+ return []
71
+
72
+ def store(self, target: Node, key: int, value: str) -> bool:
73
+ """Ask target to store key=value."""
74
+ try:
75
+ stub = self._get_stub(target)
76
+ req = neuroshard_pb2.DHTStoreRequest(
77
+ sender=node_to_proto(self.local_node),
78
+ key=key.to_bytes(20, byteorder='big'),
79
+ value=value
80
+ )
81
+ resp = stub.DHTStore(req, timeout=5.0)
82
+
83
+ self.routing_table.add_contact(proto_to_node(resp.responder))
84
+ return resp.success
85
+ except grpc.RpcError:
86
+ return False
87
+
88
+ def find_value(self, target: Node, key: int):
89
+ """Ask target for value at key."""
90
+ # Returns (value: str | None, nodes: List[Node])
91
+ try:
92
+ stub = self._get_stub(target)
93
+ req = neuroshard_pb2.DHTFindValueRequest(
94
+ sender=node_to_proto(self.local_node),
95
+ key=key.to_bytes(20, byteorder='big')
96
+ )
97
+ resp = stub.DHTFindValue(req, timeout=5.0)
98
+
99
+ self.routing_table.add_contact(proto_to_node(resp.responder))
100
+
101
+ if resp.found:
102
+ return (resp.value, [])
103
+ else:
104
+ nodes = [proto_to_node(n) for n in resp.nodes]
105
+ return (None, nodes)
106
+ except grpc.RpcError:
107
+ return (None, [])
108
+
109
+ # --- High Level Lookup Algorithm (Iterative) ---
110
+
111
+ def lookup_node(self, target_id: int) -> List[Node]:
112
+ """
113
+ Standard Kademlia Lookup
114
+ """
115
+ shortlist = self.routing_table.find_closest(target_id)
116
+ if not shortlist:
117
+ return []
118
+
119
+ visited = set()
120
+ visited.add(self.local_node.id) # Don't query self
121
+
122
+ active_queries = 0
123
+ alpha = 3
124
+
125
+ # Iterative lookup
126
+ converged = False
127
+ while not converged:
128
+ candidates = [n for n in shortlist if n.id not in visited][:alpha]
129
+ if not candidates:
130
+ break
131
+
132
+ results_found = False
133
+ for node in candidates:
134
+ visited.add(node.id)
135
+
136
+ new_nodes = self.find_node(node, target_id)
137
+ if new_nodes:
138
+ results_found = True
139
+ for n in new_nodes:
140
+ if n.id != self.local_node.id:
141
+ self.routing_table.add_contact(n)
142
+ # Add to shortlist if not already there
143
+ if n not in shortlist:
144
+ shortlist.append(n)
145
+
146
+ # Re-sort
147
+ shortlist.sort(key=lambda n: n.id ^ target_id)
148
+ # K-bucket size limit
149
+ shortlist = shortlist[:20]
150
+
151
+ if not results_found:
152
+ converged = True
153
+
154
+ return shortlist
155
+
156
+ def lookup_value(self, key: int) -> Optional[str]:
157
+ """
158
+ Find a value in the DHT.
159
+ Returns the value if found, None otherwise.
160
+ """
161
+ shortlist = self.routing_table.find_closest(key)
162
+ if not shortlist:
163
+ return None
164
+
165
+ visited = set()
166
+ visited.add(self.local_node.id)
167
+
168
+ converged = False
169
+ while not converged:
170
+ candidates = [n for n in shortlist if n.id not in visited][:3]
171
+ if not candidates:
172
+ break
173
+
174
+ results_found = False
175
+ for node in candidates:
176
+ visited.add(node.id)
177
+
178
+ val, nodes = self.find_value(node, key)
179
+ if val:
180
+ return val # Found it!
181
+
182
+ if nodes:
183
+ results_found = True
184
+ for n in nodes:
185
+ if n.id != self.local_node.id:
186
+ self.routing_table.add_contact(n)
187
+ if n not in shortlist:
188
+ shortlist.append(n)
189
+
190
+ shortlist.sort(key=lambda n: n.id ^ key)
191
+ shortlist = shortlist[:20]
192
+
193
+ if not results_found:
194
+ converged = True
195
+
196
+ return None
197
+
198
+ def announce(self, key_string: str):
199
+ """
200
+ Announce a string key (e.g. "layer_0") to the DHT.
201
+ The key is hashed to find the location.
202
+ Value is our connection info.
203
+ """
204
+ import hashlib
205
+ import json
206
+ # Hash the key string to get the 160-bit Key ID
207
+ key_id = int(hashlib.sha1(key_string.encode()).hexdigest(), 16)
208
+ value = f"{self.local_node.ip}:{self.local_node.port}"
209
+
210
+ # CRITICAL: ALWAYS store locally so other nodes can find us!
211
+ # When we're a solo node, we ARE the closest node to any key.
212
+ # Without local storage, DHT lookups will fail.
213
+ try:
214
+ # Store as list to support multiple holders
215
+ existing = self.storage.get(key_id)
216
+ if existing:
217
+ holders = json.loads(existing)
218
+ if value not in holders:
219
+ holders.append(value)
220
+ else:
221
+ holders = [value]
222
+ self.storage[key_id] = json.dumps(holders)
223
+ except Exception as e:
224
+ logger.debug(f"Local DHT storage failed: {e}")
225
+
226
+ # Find K closest nodes to the KEY ID (for replication to other nodes)
227
+ nodes = self.lookup_node(key_id)
228
+
229
+ store_count = 0
230
+ for node in nodes:
231
+ try:
232
+ if self.store(node, key_id, value):
233
+ store_count += 1
234
+ except: pass
235
+
236
+ if store_count > 0:
237
+ # Rate limit success logs to avoid spam (heartbeats happen every 10s)
238
+ now = time.time()
239
+ last_success = getattr(self, '_last_announce_success', {}).get(key_string, 0)
240
+ if not hasattr(self, '_last_announce_success'):
241
+ self._last_announce_success = {}
242
+
243
+ # Only log first announce and then every 5 minutes
244
+ if last_success == 0 or (now - last_success) > 300:
245
+ logger.info(f"DHT Announce success: Stored '{key_string}' on {store_count} nodes.")
246
+ self._last_announce_success[key_string] = now
247
+ else:
248
+ # Rate limit all DHT announce logs to avoid spam
249
+ now = time.time()
250
+ last_log = self._last_no_peers_log.get(key_string, 0)
251
+ if now - last_log > 60: # Rate limit: once per minute per key
252
+ if len(nodes) == 0:
253
+ # No peers found - expected when you're the first/only node
254
+ logger.debug(f"DHT Announce: No peers found to store '{key_string}' (this is normal when you're the first node).")
255
+ elif len(nodes) <= 3:
256
+ # Few nodes found and store failed - common in small networks or Docker
257
+ logger.debug(f"DHT Announce: Store failed for '{key_string}' (found {len(nodes)} nodes). This is normal in small networks.")
258
+ else:
259
+ # Found many nodes but all failed - this might be a real problem
260
+ logger.warning(f"DHT Announce failed: Could not store '{key_string}' (found {len(nodes)} nodes but store failed).")
261
+ self._last_no_peers_log[key_string] = now