astreum 0.1.12__py3-none-any.whl → 0.1.13__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/node/__init__.py CHANGED
@@ -3,6 +3,7 @@ import hashlib
3
3
  import time
4
4
  from typing import Tuple, Optional
5
5
  import json
6
+ from cryptography.hazmat.primitives.asymmetric import ed25519
6
7
 
7
8
  from .relay import Relay, Topic
8
9
  from .relay.peer import Peer
@@ -15,9 +16,33 @@ class Node:
15
16
  def __init__(self, config: dict):
16
17
  # Ensure config is a dictionary, but allow it to be None
17
18
  self.config = config if config is not None else {}
19
+
20
+ # Handle validation key if provided
21
+ self.validation_private_key = None
22
+ self.validation_public_key = None
23
+ self.is_validator = False
24
+
25
+ # Extract validation private key from config
26
+ if 'validation_private_key' in self.config:
27
+ try:
28
+ key_bytes = bytes.fromhex(self.config['validation_private_key'])
29
+ self.validation_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(key_bytes)
30
+ self.validation_public_key = self.validation_private_key.public_key()
31
+ self.is_validator = True
32
+
33
+ # Set validation_route to True in config so relay will join validation route
34
+ self.config['validation_route'] = True
35
+ print(f"Node is configured as a validator with validation key")
36
+ except Exception as e:
37
+ print(f"Error loading validation private key: {e}")
38
+
39
+ # Initialize relay with our config
18
40
  self.relay = Relay(self.config)
19
- # Get the node_id from relay instead of generating our own
41
+
42
+ # Get the node_id from relay
20
43
  self.node_id = self.relay.node_id
44
+
45
+ # Initialize storage
21
46
  self.storage = Storage(self.config)
22
47
  self.storage.node = self # Set the storage node reference to self
23
48
 
@@ -397,48 +422,64 @@ class Node:
397
422
 
398
423
  def _handle_transaction(self, body: bytes, addr: Tuple[str, int], envelope):
399
424
  """
400
- Handle receipt of a transaction.
401
- Accept if validation route is present and counter is valid relative to the latest block in our chain.
425
+ Handle incoming transaction messages.
426
+
427
+ This method is called when we receive a transaction from the network.
428
+ Transactions should only be processed by validator nodes.
429
+
430
+ Args:
431
+ body: Transaction data
432
+ addr: Source address
433
+ envelope: Full message envelope
402
434
  """
435
+ # Ignore if we're not a validator (don't have a validation key)
436
+ if not self.is_validator or not self.relay.is_in_validation_route():
437
+ print("Ignoring transaction as we're not a validator")
438
+ return
439
+
403
440
  try:
404
- # Check if we're in the validation route
405
- # This is now already checked by the relay's _handle_message method
406
- if not self.relay.is_in_validation_route():
407
- return
441
+ # Parse transaction data
442
+ tx_data = json.loads(body.decode('utf-8'))
408
443
 
409
- # Deserialize the transaction
410
- transaction = Transaction.from_bytes(body)
411
- if not transaction:
412
- return
413
-
414
- # Check if we're following this chain
415
- if not self.machine.is_following_chain(transaction.chain_id):
416
- return
417
-
418
- # Verify transaction has a valid validation route
419
- if not transaction.has_valid_route():
420
- return
421
-
422
- # Get latest block from this chain
423
- latest_block = self.machine.get_latest_block(transaction.chain_id)
424
- if not latest_block:
425
- return
426
-
427
- # Verify transaction counter is valid relative to the latest block
428
- if not transaction.is_counter_valid(latest_block):
429
- return
444
+ # Store the transaction in our local storage
445
+ tx_hash = bytes.fromhex(tx_data.get('hash'))
446
+ tx_raw = bytes.fromhex(tx_data.get('data'))
447
+
448
+ # Create transaction entry in storage
449
+ if not self.storage.contains(tx_hash):
450
+ self.storage.put(tx_hash, tx_raw)
451
+ print(f"Stored transaction {tx_hash.hex()}")
430
452
 
431
- # Process the valid transaction
432
- self.machine.process_transaction(transaction)
433
-
434
- # Relay to other peers in the validation route
435
- validation_peers = self.relay.get_route_peers(1) # 1 = validation route
436
- for peer in validation_peers:
437
- if peer.address != addr: # Don't send back to originator
438
- self.relay.send_message(body, Topic.TRANSACTION, peer.address)
453
+ # Process the transaction as a validator
454
+ self._process_transaction_as_validator(tx_hash, tx_raw)
455
+
439
456
  except Exception as e:
440
457
  print(f"Error handling transaction: {e}")
441
458
 
459
+ def _process_transaction_as_validator(self, tx_hash: bytes, tx_raw: bytes):
460
+ """
461
+ Process a transaction as a validator node.
462
+
463
+ This method is called when we receive a transaction and we're a validator.
464
+ It verifies the transaction and may include it in a future block.
465
+
466
+ Args:
467
+ tx_hash: Transaction hash
468
+ tx_raw: Raw transaction data
469
+ """
470
+ try:
471
+ print(f"Processing transaction {tx_hash.hex()} as validator")
472
+ # Here we would verify the transaction and potentially queue it
473
+ # for inclusion in the next block we create
474
+
475
+ # For now, just log that we processed it
476
+ print(f"Verified transaction {tx_hash.hex()}")
477
+
478
+ # TODO: Implement transaction validation and queueing for block creation
479
+
480
+ except Exception as e:
481
+ print(f"Error processing transaction as validator: {e}")
482
+
442
483
  def _initialize_latest_block(self):
443
484
  """Initialize latest block from storage if available."""
444
485
  # Implementation would load the latest block from storage
@@ -24,10 +24,10 @@ class Relay:
24
24
  self.num_workers = config.get('num_workers', 4)
25
25
 
26
26
  # Generate Ed25519 keypair for this node
27
- if 'private_key' in config:
27
+ if 'relay_private_key' in config:
28
28
  # Load existing private key if provided
29
29
  try:
30
- private_key_bytes = bytes.fromhex(config['private_key'])
30
+ private_key_bytes = bytes.fromhex(config['relay_private_key'])
31
31
  self.private_key = ed25519.Ed25519PrivateKey.from_private_bytes(private_key_bytes)
32
32
  except Exception as e:
33
33
  print(f"Error loading private key: {e}, generating new one")
@@ -49,6 +49,8 @@ class Relay:
49
49
  # Peer route is always enabled
50
50
  self.routes.append(0) # Peer route
51
51
 
52
+ # Check if the node should join validation route
53
+ # This is now controlled by the parent Node class based on validation_private_key
52
54
  if config.get('validation_route', False):
53
55
  self.routes.append(1) # Validation route
54
56
 
@@ -101,26 +103,6 @@ class Relay:
101
103
  """Check if this node is part of the validation route."""
102
104
  return 1 in self.routes
103
105
 
104
- def add_to_peer_route(self):
105
- """Add this node to the peer route."""
106
- if 0 not in self.routes:
107
- self.routes.append(0)
108
-
109
- def add_to_validation_route(self):
110
- """Add this node to the validation route."""
111
- if 1 not in self.routes:
112
- self.routes.append(1)
113
-
114
- def remove_from_peer_route(self):
115
- """Remove this node from the peer route."""
116
- if 0 in self.routes:
117
- self.routes.remove(0)
118
-
119
- def remove_from_validation_route(self):
120
- """Remove this node from the validation route."""
121
- if 1 in self.routes:
122
- self.routes.remove(1)
123
-
124
106
  def add_peer_to_route(self, peer: Peer, route_types: List[int]):
125
107
  """
126
108
  Add a peer to specified routes.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: astreum
3
- Version: 0.1.12
3
+ Version: 0.1.13
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
@@ -28,7 +28,8 @@ When initializing an Astreum Node, you need to provide a configuration dictionar
28
28
 
29
29
  | Parameter | Type | Default | Description |
30
30
  |-----------|------|---------|-------------|
31
- | `private_key` | string | Auto-generated | Hex string of Ed25519 private key. If not provided, a new keypair will be generated automatically |
31
+ | `relay_private_key` | string | Auto-generated | Hex string of Ed25519 private key for network identity. If not provided, a new keypair will be generated automatically |
32
+ | `validation_private_key` | string | None | Hex string of Ed25519 private key for block validation. If provided, the node will join the validation route automatically |
32
33
  | `storage_path` | string | "storage" | Path to store data |
33
34
  | `max_storage_space` | int | 1073741824 (1GB) | Maximum storage space in bytes |
34
35
  | `max_object_recursion` | int | 50 | Maximum recursion depth for resolving nested objects |
@@ -47,7 +48,7 @@ When initializing an Astreum Node, you need to provide a configuration dictionar
47
48
 
48
49
  | Parameter | Type | Default | Description |
49
50
  |-----------|------|---------|-------------|
50
- | `validation_route` | bool | False | Whether to participate in the block validation route |
51
+ | `validation_route` | bool | False | Whether to participate in the block validation route (automatically set to True if validation_private_key is provided) |
51
52
  | `bootstrap_peers` | list | [] | List of bootstrap peers in the format `[("hostname", port), ...]` |
52
53
 
53
54
  > **Note:** The peer route is always enabled as it's necessary for object discovery and retrieval.
@@ -59,12 +60,11 @@ from astreum.node import Node
59
60
 
60
61
  # Configuration dictionary
61
62
  config = {
62
- "private_key": "my-private-key-goes-here",
63
+ "relay_private_key": "relay-private-key-hex-string",
64
+ "validation_private_key": "validation-private-key-hex-string", # Optional, for validator nodes
63
65
  "storage_path": "./data/node1",
64
66
  "incoming_port": 7373,
65
67
  "use_ipv6": False,
66
- "peer_route": True,
67
- "validation_route": True,
68
68
  "bootstrap_peers": [
69
69
  ("bootstrap.astreum.org", 7373),
70
70
  ("127.0.0.1", 7374)
@@ -20,9 +20,9 @@ astreum/lispeum/special/number/addition.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
20
20
  astreum/machine/__init__.py,sha256=GOdZl1tS9uIJHbq5WVcplifMDPDLQroX7CVew-K2YbA,15262
21
21
  astreum/machine/environment.py,sha256=K0084U6B7wwjrDZ9b2_7cEcbBzsB7UOy_Zpbrr7B3GY,834
22
22
  astreum/machine/error.py,sha256=MvqBaZZt33rNELNhUJ2lER3TE3aS8WVqsWF2hz2AwoA,38
23
- astreum/node/__init__.py,sha256=EdGMa9pargAdB7KzjKBkhuFJ3G3wZF2VeIGkYFOCLws,22497
23
+ astreum/node/__init__.py,sha256=VlyhTLOjqy5VJlcLiTfTqgcsWuN3mudv_WtM5ixrojc,24121
24
24
  astreum/node/models.py,sha256=9Uf2_u55uxWG0ujjySvFJUO5Ub-EzlMnnMJWcgJHjHk,11980
25
- astreum/node/relay/__init__.py,sha256=gQNYDxllkjZqE6bvgPOYkKu3QHkjPFn11RvtP-BxtKI,13994
25
+ astreum/node/relay/__init__.py,sha256=k-_lEenUvLnBriSqjsqpnbwua1j6ZUghqkGD_Jc9ZYM,13493
26
26
  astreum/node/relay/bucket.py,sha256=pcmollbbM-xeHlmDxLZnzvf0Ut-9v9RoN6SijYiQuu8,2893
27
27
  astreum/node/relay/envelope.py,sha256=TfkynttoPX7smvMV7xEAdtIlfz-Z-EZjuhZ826csZxA,10078
28
28
  astreum/node/relay/message.py,sha256=uezmGjNaQK4fZmYQLCHd2YpiosaaFb8DOa3H58HS1jA,2887
@@ -30,8 +30,8 @@ astreum/node/relay/peer.py,sha256=DlvTR9j0BZQ1dW-p_9UGgfLvQqwNdpNLMSCYEW4FhyI,58
30
30
  astreum/node/relay/route.py,sha256=fyOSsAe1mfsCVeN6LtQ_OEUEb1FiC5dobZBEJKNGU9U,5814
31
31
  astreum/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
32
32
  astreum/utils/bytes_format.py,sha256=X4tG5GGPweNCE54bHYkLFiuLTbmpy5upO_s1Cef-MGA,2711
33
- astreum-0.1.12.dist-info/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
34
- astreum-0.1.12.dist-info/METADATA,sha256=LnGyI9YKLRNRWLolnyuHDgg0MKPSyLSwJho4FCTg1to,2942
35
- astreum-0.1.12.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
36
- astreum-0.1.12.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
37
- astreum-0.1.12.dist-info/RECORD,,
33
+ astreum-0.1.13.dist-info/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
34
+ astreum-0.1.13.dist-info/METADATA,sha256=0wxUc4qtd3ipFd3-IwFjDcsWTBqAK8I-u3hrgBmgVX8,3261
35
+ astreum-0.1.13.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
36
+ astreum-0.1.13.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
37
+ astreum-0.1.13.dist-info/RECORD,,