astreum 0.2.37__py3-none-any.whl → 0.2.38__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.

@@ -1,7 +1,8 @@
1
1
  import socket, threading
2
2
  from queue import Queue
3
3
  from typing import Tuple, Optional
4
- from cryptography.hazmat.primitives.asymmetric import ed25519
4
+ from cryptography.hazmat.primitives.asymmetric import ed25519
5
+ from cryptography.hazmat.primitives import serialization
5
6
  from cryptography.hazmat.primitives.asymmetric.x25519 import (
6
7
  X25519PrivateKey,
7
8
  X25519PublicKey,
@@ -67,10 +68,18 @@ def communication_setup(node: "Node", config: dict):
67
68
 
68
69
  # key loading
69
70
  node.relay_secret_key = load_x25519(config.get('relay_secret_key'))
70
- node.validation_secret_key = load_ed25519(config.get('validation_secret_key'))
71
-
72
- # derive pubs + routes
73
- node.relay_public_key = node.relay_secret_key.public_key()
71
+ node.validation_secret_key = load_ed25519(config.get('validation_secret_key'))
72
+
73
+ # derive pubs + routes
74
+ node.relay_public_key = node.relay_secret_key.public_key()
75
+ node.validation_public_key = (
76
+ node.validation_secret_key.public_key().public_bytes(
77
+ encoding=serialization.Encoding.Raw,
78
+ format=serialization.PublicFormat.Raw,
79
+ )
80
+ if node.validation_secret_key
81
+ else None
82
+ )
74
83
  node.peer_route, node.validation_route = make_routes(
75
84
  node.relay_public_key,
76
85
  node.validation_secret_key
@@ -2,15 +2,38 @@ from __future__ import annotations
2
2
 
3
3
  import threading
4
4
  import time
5
- from queue import Queue, Empty
5
+ from dataclasses import dataclass
6
+ from queue import Empty, Queue
6
7
  from typing import Any, Dict, Optional, Tuple
7
8
 
9
+ from cryptography.hazmat.primitives import serialization
10
+
8
11
  from .block import Block
9
12
  from .chain import Chain
10
13
  from .fork import Fork
11
14
  from .._storage.atom import ZERO32, Atom
12
15
 
13
16
 
17
+ @dataclass
18
+ class Transaction:
19
+ """Lightweight transaction view for validation processing."""
20
+
21
+ recipient: bytes
22
+ sender: bytes
23
+ amount: int
24
+ counter: int
25
+
26
+
27
+ def current_validator(node: Any) -> bytes:
28
+ """Return the current validator identifier. Override downstream."""
29
+ raise NotImplementedError("current_validator must be implemented by the host node")
30
+
31
+
32
+ def apply_transaction(node: Any, block: object, transaction_hash: bytes) -> None:
33
+ """Apply transaction to the candidate block. Override downstream."""
34
+ pass
35
+
36
+
14
37
  def validation_setup(node: Any) -> None:
15
38
  # Shared state
16
39
  node.validation_lock = getattr(node, "validation_lock", threading.RLock())
@@ -21,6 +44,10 @@ def validation_setup(node: Any) -> None:
21
44
  node.chains = getattr(node, "chains", {})
22
45
  node.forks = getattr(node, "forks", {})
23
46
 
47
+ # Pending transactions queue (hash-only entries)
48
+ node._validation_transaction_queue = getattr(
49
+ node, "_validation_transaction_queue", Queue()
50
+ )
24
51
  # Single work queue of grouped items: (latest_block_hash, set(peer_ids))
25
52
  node._validation_verify_queue = getattr(
26
53
  node, "_validation_verify_queue", Queue()
@@ -29,6 +56,14 @@ def validation_setup(node: Any) -> None:
29
56
  node, "_validation_stop_event", threading.Event()
30
57
  )
31
58
 
59
+ def enqueue_transaction_hash(tx_hash: bytes) -> None:
60
+ """Schedule a transaction hash for validation processing."""
61
+ if not isinstance(tx_hash, (bytes, bytearray)):
62
+ raise TypeError("transaction hash must be bytes-like")
63
+ node._validation_transaction_queue.put(bytes(tx_hash))
64
+
65
+ node.enqueue_transaction_hash = enqueue_transaction_hash
66
+
32
67
  def _process_peers_latest_block(latest_block_hash: bytes, peer_ids: set[Any]) -> None:
33
68
  """Assign a peer to a fork for its latest block without merging forks.
34
69
 
@@ -130,6 +165,46 @@ def validation_setup(node: Any) -> None:
130
165
  except Exception:
131
166
  pass
132
167
 
168
+ def _validation_worker() -> None:
169
+ """Consume pending transactions when scheduled to validate."""
170
+ stop = node._validation_stop_event
171
+ while not stop.is_set():
172
+ validation_public_key = getattr(node, "validation_public_key", None)
173
+ if not validation_public_key:
174
+ time.sleep(0.5)
175
+ continue
176
+
177
+ scheduled_validator = current_validator(node)
178
+
179
+ if scheduled_validator != validation_public_key:
180
+ time.sleep(0.5)
181
+ continue
182
+
183
+ try:
184
+ current_hash = node._validation_transaction_queue.get_nowait()
185
+ except Empty:
186
+ time.sleep(0.1)
187
+ continue
188
+
189
+ new_block = Block()
190
+ new_block.validator_public_key = getattr(node, "validation_public_key", None)
191
+
192
+ while True:
193
+ try:
194
+ apply_transaction(node, new_block, current_hash)
195
+ except NotImplementedError:
196
+ node._validation_transaction_queue.put(current_hash)
197
+ time.sleep(0.5)
198
+ break
199
+ except Exception:
200
+ # Skip problematic transaction; leave block as-is.
201
+ pass
202
+
203
+ try:
204
+ current_hash = node._validation_transaction_queue.get_nowait()
205
+ except Empty:
206
+ break
207
+
133
208
  # Start workers as daemons
134
209
  node.validation_discovery_thread = threading.Thread(
135
210
  target=_discovery_worker, daemon=True, name="validation-discovery"
@@ -137,5 +212,10 @@ def validation_setup(node: Any) -> None:
137
212
  node.validation_verify_thread = threading.Thread(
138
213
  target=_verify_worker, daemon=True, name="validation-verify"
139
214
  )
215
+ node.validation_worker_thread = threading.Thread(
216
+ target=_validation_worker, daemon=True, name="validation-worker"
217
+ )
140
218
  node.validation_discovery_thread.start()
141
219
  node.validation_verify_thread.start()
220
+ if getattr(node, "validation_secret_key", None):
221
+ node.validation_worker_thread.start()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astreum
3
- Version: 0.2.37
3
+ Version: 0.2.38
4
4
  Summary: Python library to interact with the Astreum blockchain and its Lispeum virtual machine.
5
5
  Author-email: "Roy R. O. Okello" <roy@stelar.xyz>
6
6
  Project-URL: Homepage, https://github.com/astreum/lib
@@ -5,7 +5,7 @@ astreum/node.py,sha256=SuVm1b0QWl1FpDUaLRH1fiFYnXCrPs6qYeUQlPDae8w,38358
5
5
  astreum/_communication/__init__.py,sha256=I6TVFC1KXtwwdCjKUkGjOhsLWfC7cECubjzqmm-SwRs,161
6
6
  astreum/_communication/peer.py,sha256=DT2vJOzeLyyOj7vTDQ1u1lF5Vc7Epj0Hhie-YfDrzfA,425
7
7
  astreum/_communication/route.py,sha256=enWT_1260LJq-L-zK-jtacQ8LbZGquNO9yj-9IglSXE,1232
8
- astreum/_communication/setup.py,sha256=IzT23T1LNpseJ2m3G1J4g6oXKdywT14g-Saffi2NSqA,3544
8
+ astreum/_communication/setup.py,sha256=6KH144iaHNec9g4cvC8fcLIBY0dvx5OCjV5WVYKNcZo,3865
9
9
  astreum/_lispeum/__init__.py,sha256=LAy2Z-gBBQlByBHRGUKaaQrOB7QzFEEyGRtInmwTpfU,304
10
10
  astreum/_lispeum/environment.py,sha256=pJ0rjp9GoQxHhDiPIVei0jP7dZ_Pznso2O_tpp94-Ik,328
11
11
  astreum/_lispeum/expression.py,sha256=io8tbCer_1TJee77yRbcNI5q-DPFGa8xZiC80tGvRRQ,1063
@@ -21,7 +21,7 @@ astreum/_validation/block.py,sha256=4ImViawnG0bhN-TiCk3F0byTlPm9U0l6PdSL53u3bsc,
21
21
  astreum/_validation/chain.py,sha256=lOFbz5z0AOeMLchQ2YPRSbIZIdQlnHqDyMJvgdwJ-Iw,2532
22
22
  astreum/_validation/fork.py,sha256=ZGTOVEhSiYJvvLvlC6FV8Zqe62uLTM-cSS3yKrKrLvA,3602
23
23
  astreum/_validation/genesis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- astreum/_validation/setup.py,sha256=VSuCtLBZ3ieHHlJl3EkI5n4mEjRpgJ9hfKGxeGSrAVo,5592
24
+ astreum/_validation/setup.py,sha256=FLutAEpW1Hh0WpGz1_k18tspc4z2RXA6hOHVaF-BmhY,8442
25
25
  astreum/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
26
  astreum/crypto/ed25519.py,sha256=FRnvlN0kZlxn4j-sJKl-C9tqiz_0z4LZyXLj3KIj1TQ,1760
27
27
  astreum/crypto/quadratic_form.py,sha256=pJgbORey2NTWbQNhdyvrjy_6yjORudQ67jBz2ScHptg,4037
@@ -47,8 +47,8 @@ astreum/relay/setup.py,sha256=ynvGaJdlDtw_f5LLiow2Wo7IRzUjvgk8eSr1Sv4_zTg,2090
47
47
  astreum/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  astreum/storage/object.py,sha256=knFlvw_tpcC4twSu1DGNpHX31wlANN8E5dgEqIfU--Q,2041
49
49
  astreum/storage/setup.py,sha256=1-9ztEFI_BvRDvAA0lAn4mFya8iq65THTArlj--M3Hg,626
50
- astreum-0.2.37.dist-info/licenses/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
51
- astreum-0.2.37.dist-info/METADATA,sha256=6VjD2A-MyBa-ahLWr_pJN69GO4lBjcFgv4So48JCsvo,6181
52
- astreum-0.2.37.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
- astreum-0.2.37.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
54
- astreum-0.2.37.dist-info/RECORD,,
50
+ astreum-0.2.38.dist-info/licenses/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
51
+ astreum-0.2.38.dist-info/METADATA,sha256=c-g2CirbWXU3Le0Fi6f1LJY_cJvTllbyEuTTM3PkeWE,6181
52
+ astreum-0.2.38.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
+ astreum-0.2.38.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
54
+ astreum-0.2.38.dist-info/RECORD,,