astreum 0.1.18__py3-none-any.whl → 0.1.19__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/node/__init__.py CHANGED
@@ -1,475 +1,447 @@
1
- # import time
2
- # import threading
3
- # from typing import List
4
- # from cryptography.hazmat.primitives.asymmetric import ed25519
5
- # from cryptography.hazmat.primitives import serialization
1
+ import time
2
+ import threading
3
+ from typing import List
4
+ from cryptography.hazmat.primitives.asymmetric import ed25519
5
+ from cryptography.hazmat.primitives import serialization
6
6
 
7
- # from .relay import Relay, Topic
8
- # from .machine import AstreumMachine
9
- # from .utils import hash_data
10
- # from .validation.block import Block
11
- # from .storage import Storage
7
+ from .relay import Relay, Topic
8
+ from ..machine import AstreumMachine
9
+ from .utils import hash_data
10
+ from .validation.block import Block
11
+ from .storage import Storage
12
12
 
13
- # # Import our validation components using the new functional approach
14
- # from .validation import (
15
- # validate_block,
16
- # create_block,
17
- # create_genesis_block,
18
- # compute_vdf,
19
- # verify_vdf,
20
- # select_validator,
21
- # select_validator_for_slot,
22
- # get_validator_stake,
23
- # is_validator,
24
- # VALIDATION_ADDRESS,
25
- # BURN_ADDRESS,
26
- # MIN_STAKE_AMOUNT,
27
- # SLOT_DURATION,
28
- # VDF_DIFFICULTY
29
- # )
30
- # from .validation.state import (
31
- # add_block_to_state,
32
- # validate_and_apply_block,
33
- # create_account_state,
34
- # get_validator_for_slot,
35
- # select_best_chain,
36
- # compare_chains,
37
- # get_validator_set
38
- # )
39
- # from .validation.adapter import BlockAdapter, TransactionAdapter
40
-
41
- # class Node:
42
- # def __init__(self, config: dict):
43
- # # Ensure config is a dictionary, but allow it to be None
44
- # self.config = config if config is not None else {}
45
-
46
- # # Handle validation key if provided
47
- # self.validation_private_key = None
48
- # self.validation_public_key = None
49
- # self.is_validator = False
50
-
51
- # # Extract validation private key from config
52
- # if 'validation_private_key' in self.config:
53
- # try:
54
- # key_bytes = bytes.fromhex(self.config['validation_private_key'])
55
- # self.validation_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(key_bytes)
56
- # self.validation_public_key = self.validation_private_key.public_key()
57
- # self.is_validator = True
13
+ class Node:
14
+ def __init__(self, config: dict):
15
+ # Ensure config is a dictionary, but allow it to be None
16
+ self.config = config if config is not None else {}
17
+
18
+ # Handle validation key if provided
19
+ self.validation_private_key = None
20
+ self.validation_public_key = None
21
+ self.is_validator = False
22
+
23
+ # Extract validation private key from config
24
+ if 'validation_private_key' in self.config:
25
+ try:
26
+ key_bytes = bytes.fromhex(self.config['validation_private_key'])
27
+ self.validation_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(key_bytes)
28
+ self.validation_public_key = self.validation_private_key.public_key()
29
+ self.is_validator = True
58
30
 
59
- # # Set validation_route to True in config so relay will join validation route
60
- # self.config['validation_route'] = True
61
- # print(f"Node is configured as a validator with validation key")
62
- # except Exception as e:
63
- # print(f"Error loading validation private key: {e}")
64
-
65
- # # Initialize relay with our config
66
- # self.relay = Relay(self.config)
67
-
68
- # # Get the node_id from relay
69
- # self.node_id = self.relay.node_id
70
-
71
- # # Initialize storage
72
- # self.storage = Storage(self.config)
73
- # self.storage.node = self # Set the storage node reference to self
74
-
75
- # # Initialize blockchain state
76
- # self.blockchain = create_account_state(self.config)
77
-
78
- # # Store our validator info if we're a validator
79
- # if self.is_validator and self.validation_public_key:
80
- # self.validator_address = self.validation_public_key.public_bytes(
81
- # encoding=serialization.Encoding.Raw,
82
- # format=serialization.PublicFormat.Raw
83
- # )
84
- # self.validator_private_bytes = self.validation_private_key.private_bytes(
85
- # encoding=serialization.Encoding.Raw,
86
- # format=serialization.PrivateFormat.Raw,
87
- # encryption_algorithm=serialization.NoEncryption()
88
- # )
89
- # print(f"Registered validator with address: {self.validator_address.hex()}")
90
- # else:
91
- # self.validator_address = None
92
- # self.validator_private_bytes = None
93
-
94
- # # Latest block of the chain this node is following
95
- # self.latest_block = None
96
- # self.followed_chain_id = self.config.get('followed_chain_id', None)
97
-
98
- # # Initialize machine
99
- # self.machine = AstreumMachine(node=self)
100
-
101
- # # Register message handlers
102
- # self.relay.message_handlers[Topic.PEER_ROUTE] = self._handle_peer_route
103
- # self.relay.message_handlers[Topic.PING] = self._handle_ping
104
- # self.relay.message_handlers[Topic.PONG] = self._handle_pong
105
- # self.relay.message_handlers[Topic.OBJECT_REQUEST] = self._handle_object_request
106
- # self.relay.message_handlers[Topic.OBJECT_RESPONSE] = self._handle_object_response
107
- # self.relay.message_handlers[Topic.ROUTE_REQUEST] = self._handle_route_request
108
- # self.relay.message_handlers[Topic.ROUTE] = self._handle_route
109
- # self.relay.message_handlers[Topic.LATEST_BLOCK_REQUEST] = self._handle_latest_block_request
110
- # self.relay.message_handlers[Topic.LATEST_BLOCK] = self._handle_latest_block
111
- # self.relay.message_handlers[Topic.TRANSACTION] = self._handle_transaction
112
- # self.relay.message_handlers[Topic.BLOCK_REQUEST] = self._handle_block_request
113
- # self.relay.message_handlers[Topic.BLOCK_RESPONSE] = self._handle_block_response
114
-
115
- # # Initialize latest block from storage if available
116
- # self._initialize_latest_block()
117
-
118
- # # Candidate chains that might be adopted
119
- # self.candidate_chains = {} # chain_id -> {'latest_block': block, 'timestamp': time.time()}
120
- # self.pending_blocks = {} # block_hash -> {'block': block, 'timestamp': time.time()}
121
-
122
- # # Threads for validation and chain monitoring
123
- # self.running = False
124
- # self.main_chain_validation_thread = None
125
- # self.candidate_chain_validation_thread = None
126
-
127
- # # Pending transactions for a block
128
- # self.pending_transactions = {} # tx_hash -> {'transaction': tx, 'timestamp': time.time()}
129
-
130
- # # Last block production attempt time
131
- # self.last_block_attempt_time = 0
31
+ # Set validation_route to True in config so relay will join validation route
32
+ self.config['validation_route'] = True
33
+ print(f"Node is configured as a validator with validation key")
34
+ except Exception as e:
35
+ print(f"Error loading validation private key: {e}")
36
+
37
+ # Initialize relay with our config
38
+ self.relay = Relay(self.config)
39
+
40
+ # Get the node_id from relay
41
+ self.node_id = self.relay.node_id
42
+
43
+ # Initialize storage
44
+ self.storage = Storage(self.config)
45
+ self.storage.node = self # Set the storage node reference to self
46
+
47
+ # Initialize blockchain state
48
+ self.blockchain = create_account_state(self.config)
49
+
50
+ # Store our validator info if we're a validator
51
+ if self.is_validator and self.validation_public_key:
52
+ self.validator_address = self.validation_public_key.public_bytes(
53
+ encoding=serialization.Encoding.Raw,
54
+ format=serialization.PublicFormat.Raw
55
+ )
56
+ self.validator_private_bytes = self.validation_private_key.private_bytes(
57
+ encoding=serialization.Encoding.Raw,
58
+ format=serialization.PrivateFormat.Raw,
59
+ encryption_algorithm=serialization.NoEncryption()
60
+ )
61
+ print(f"Registered validator with address: {self.validator_address.hex()}")
62
+ else:
63
+ self.validator_address = None
64
+ self.validator_private_bytes = None
65
+
66
+ # Latest block of the chain this node is following
67
+ self.latest_block = None
68
+ self.followed_chain_id = self.config.get('followed_chain_id', None)
69
+
70
+ # Initialize machine
71
+ self.machine = AstreumMachine(node=self)
72
+
73
+ # Register message handlers
74
+ self.relay.message_handlers[Topic.PEER_ROUTE] = self._handle_peer_route
75
+ self.relay.message_handlers[Topic.PING] = self._handle_ping
76
+ self.relay.message_handlers[Topic.PONG] = self._handle_pong
77
+ self.relay.message_handlers[Topic.OBJECT_REQUEST] = self._handle_object_request
78
+ self.relay.message_handlers[Topic.OBJECT_RESPONSE] = self._handle_object_response
79
+ self.relay.message_handlers[Topic.ROUTE_REQUEST] = self._handle_route_request
80
+ self.relay.message_handlers[Topic.ROUTE] = self._handle_route
81
+ self.relay.message_handlers[Topic.LATEST_BLOCK_REQUEST] = self._handle_latest_block_request
82
+ self.relay.message_handlers[Topic.LATEST_BLOCK] = self._handle_latest_block
83
+ self.relay.message_handlers[Topic.TRANSACTION] = self._handle_transaction
84
+ self.relay.message_handlers[Topic.BLOCK_REQUEST] = self._handle_block_request
85
+ self.relay.message_handlers[Topic.BLOCK_RESPONSE] = self._handle_block_response
86
+
87
+ # Initialize latest block from storage if available
88
+ self._initialize_latest_block()
89
+
90
+ # Candidate chains that might be adopted
91
+ self.candidate_chains = {} # chain_id -> {'latest_block': block, 'timestamp': time.time()}
92
+ self.pending_blocks = {} # block_hash -> {'block': block, 'timestamp': time.time()}
93
+
94
+ # Threads for validation and chain monitoring
95
+ self.running = False
96
+ self.main_chain_validation_thread = None
97
+ self.candidate_chain_validation_thread = None
98
+
99
+ # Pending transactions for a block
100
+ self.pending_transactions = {} # tx_hash -> {'transaction': tx, 'timestamp': time.time()}
101
+
102
+ # Last block production attempt time
103
+ self.last_block_attempt_time = 0
132
104
 
133
- # def start(self):
134
- # """Start the node."""
135
- # self.running = True
136
-
137
- # # Start relay
138
- # self.relay.start()
139
-
140
- # # Start chain monitoring thread
141
- # self.main_chain_validation_thread = threading.Thread(
142
- # target=self._main_chain_validation_loop,
143
- # name="MainChainValidation"
144
- # )
145
- # self.main_chain_validation_thread.daemon = True
146
- # self.main_chain_validation_thread.start()
147
-
148
- # self.candidate_chain_validation_thread = threading.Thread(
149
- # target=self._candidate_chain_validation_loop,
150
- # name="CandidateChainValidation"
151
- # )
152
- # self.candidate_chain_validation_thread.daemon = True
153
- # self.candidate_chain_validation_thread.start()
154
-
155
- # # Set up recurring block query tasks
156
- # main_query_thread = threading.Thread(
157
- # target=self._block_query_loop,
158
- # args=('main',),
159
- # daemon=True
160
- # )
161
- # main_query_thread.start()
162
-
163
- # validation_query_thread = threading.Thread(
164
- # target=self._block_query_loop,
165
- # args=('validation',),
166
- # daemon=True
167
- # )
168
- # validation_query_thread.start()
169
-
170
- # print(f"Node started with ID {self.node_id.hex()}")
105
+ def start(self):
106
+ """Start the node."""
107
+ self.running = True
108
+
109
+ # Start relay
110
+ self.relay.start()
111
+
112
+ # Start chain monitoring thread
113
+ self.main_chain_validation_thread = threading.Thread(
114
+ target=self._main_chain_validation_loop,
115
+ name="MainChainValidation"
116
+ )
117
+ self.main_chain_validation_thread.daemon = True
118
+ self.main_chain_validation_thread.start()
119
+
120
+ self.candidate_chain_validation_thread = threading.Thread(
121
+ target=self._candidate_chain_validation_loop,
122
+ name="CandidateChainValidation"
123
+ )
124
+ self.candidate_chain_validation_thread.daemon = True
125
+ self.candidate_chain_validation_thread.start()
126
+
127
+ # Set up recurring block query tasks
128
+ main_query_thread = threading.Thread(
129
+ target=self._block_query_loop,
130
+ args=('main',),
131
+ daemon=True
132
+ )
133
+ main_query_thread.start()
134
+
135
+ validation_query_thread = threading.Thread(
136
+ target=self._block_query_loop,
137
+ args=('validation',),
138
+ daemon=True
139
+ )
140
+ validation_query_thread.start()
141
+
142
+ print(f"Node started with ID {self.node_id.hex()}")
171
143
 
172
- # def stop(self):
173
- # """Stop the node and all its services."""
174
- # self.running = False
144
+ def stop(self):
145
+ """Stop the node and all its services."""
146
+ self.running = False
175
147
 
176
- # # Stop all threads
177
- # if self.main_chain_validation_thread and self.main_chain_validation_thread.is_alive():
178
- # self.main_chain_validation_thread.join(timeout=1.0)
148
+ # Stop all threads
149
+ if self.main_chain_validation_thread and self.main_chain_validation_thread.is_alive():
150
+ self.main_chain_validation_thread.join(timeout=1.0)
179
151
 
180
- # if self.candidate_chain_validation_thread and self.candidate_chain_validation_thread.is_alive():
181
- # self.candidate_chain_validation_thread.join(timeout=1.0)
152
+ if self.candidate_chain_validation_thread and self.candidate_chain_validation_thread.is_alive():
153
+ self.candidate_chain_validation_thread.join(timeout=1.0)
182
154
 
183
- # # Stop relay last
184
- # if self.relay:
185
- # self.relay.stop()
155
+ # Stop relay last
156
+ if self.relay:
157
+ self.relay.stop()
186
158
 
187
- # print("Node stopped")
159
+ print("Node stopped")
188
160
 
189
- # def _main_chain_validation_loop(self):
190
- # """
191
- # Main validation loop for the primary blockchain.
192
- # This thread prioritizes validating blocks on the main chain we're following.
193
- # """
194
- # while self.running:
195
- # try:
196
- # # Update latest block if we don't have one yet
197
- # if not self.latest_block and hasattr(self.blockchain, 'get_latest_block'):
198
- # self.latest_block = self.blockchain.get_latest_block()
161
+ def _main_chain_validation_loop(self):
162
+ """
163
+ Main validation loop for the primary blockchain.
164
+ This thread prioritizes validating blocks on the main chain we're following.
165
+ """
166
+ while self.running:
167
+ try:
168
+ # Update latest block if we don't have one yet
169
+ if not self.latest_block and hasattr(self.blockchain, 'get_latest_block'):
170
+ self.latest_block = self.blockchain.get_latest_block()
199
171
 
200
- # # Process any blocks that extend our main chain immediately
201
- # self._process_main_chain_blocks()
172
+ # Process any blocks that extend our main chain immediately
173
+ self._process_main_chain_blocks()
202
174
 
203
- # # Attempt block production if we are a validator
204
- # if self.is_validator and self.validator_address:
205
- # self._attempt_block_production()
175
+ # Attempt block production if we are a validator
176
+ if self.is_validator and self.validator_address:
177
+ self._attempt_block_production()
206
178
 
207
- # # Cleanup old items
208
- # self._prune_pending_items()
179
+ # Cleanup old items
180
+ self._prune_pending_items()
209
181
 
210
- # # Sleep to prevent high CPU usage
211
- # time.sleep(0.1) # Short sleep for main chain validation
212
- # except Exception as e:
213
- # print(f"Error in main chain validation loop: {e}")
214
- # time.sleep(1) # Longer sleep on error
182
+ # Sleep to prevent high CPU usage
183
+ time.sleep(0.1) # Short sleep for main chain validation
184
+ except Exception as e:
185
+ print(f"Error in main chain validation loop: {e}")
186
+ time.sleep(1) # Longer sleep on error
215
187
 
216
- # def _candidate_chain_validation_loop(self):
217
- # """
218
- # Validation loop for candidate chains (potential forks).
219
- # This thread handles validation of blocks from alternate chains
220
- # without slowing down the main chain processing.
221
- # """
222
- # while self.running:
223
- # try:
224
- # # Process candidate chains
225
- # self._evaluate_candidate_chains()
188
+ def _candidate_chain_validation_loop(self):
189
+ """
190
+ Validation loop for candidate chains (potential forks).
191
+ This thread handles validation of blocks from alternate chains
192
+ without slowing down the main chain processing.
193
+ """
194
+ while self.running:
195
+ try:
196
+ # Process candidate chains
197
+ self._evaluate_candidate_chains()
226
198
 
227
- # # Prune old candidate chains
228
- # self._prune_candidate_chains()
199
+ # Prune old candidate chains
200
+ self._prune_candidate_chains()
229
201
 
230
- # # Sleep longer for candidate chain validation (lower priority)
231
- # time.sleep(1) # Longer sleep for candidate chain validation
232
- # except Exception as e:
233
- # print(f"Error in candidate chain validation loop: {e}")
234
- # time.sleep(2) # Even longer sleep on error
202
+ # Sleep longer for candidate chain validation (lower priority)
203
+ time.sleep(1) # Longer sleep for candidate chain validation
204
+ except Exception as e:
205
+ print(f"Error in candidate chain validation loop: {e}")
206
+ time.sleep(2) # Even longer sleep on error
235
207
 
236
- # def _prune_pending_items(self):
237
- # """Remove old pending blocks and transactions."""
238
- # current_time = time.time()
239
-
240
- # # Prune old pending blocks (older than 1 hour)
241
- # blocks_to_remove = [
242
- # block_hash for block_hash, data in self.pending_blocks.items()
243
- # if current_time - data['timestamp'] > 3600 # 1 hour
244
- # ]
245
- # for block_hash in blocks_to_remove:
246
- # del self.pending_blocks[block_hash]
208
+ def _prune_pending_items(self):
209
+ """Remove old pending blocks and transactions."""
210
+ current_time = time.time()
211
+
212
+ # Prune old pending blocks (older than 1 hour)
213
+ blocks_to_remove = [
214
+ block_hash for block_hash, data in self.pending_blocks.items()
215
+ if current_time - data['timestamp'] > 3600 # 1 hour
216
+ ]
217
+ for block_hash in blocks_to_remove:
218
+ del self.pending_blocks[block_hash]
247
219
 
248
- # # Prune old pending transactions (older than 30 minutes)
249
- # txs_to_remove = [
250
- # tx_hash for tx_hash, data in self.pending_transactions.items()
251
- # if current_time - data['timestamp'] > 1800 # 30 minutes
252
- # ]
253
- # for tx_hash in txs_to_remove:
254
- # del self.pending_transactions[tx_hash]
220
+ # Prune old pending transactions (older than 30 minutes)
221
+ txs_to_remove = [
222
+ tx_hash for tx_hash, data in self.pending_transactions.items()
223
+ if current_time - data['timestamp'] > 1800 # 30 minutes
224
+ ]
225
+ for tx_hash in txs_to_remove:
226
+ del self.pending_transactions[tx_hash]
255
227
 
256
- # def _process_main_chain_blocks(self):
257
- # """
258
- # Process blocks that extend our current main chain.
259
- # Prioritizes blocks that build on our latest block.
260
- # """
261
- # # Skip if we don't have a latest block yet
262
- # if not self.latest_block:
263
- # return
228
+ def _process_main_chain_blocks(self):
229
+ """
230
+ Process blocks that extend our current main chain.
231
+ Prioritizes blocks that build on our latest block.
232
+ """
233
+ # Skip if we don't have a latest block yet
234
+ if not self.latest_block:
235
+ return
264
236
 
265
- # # Get the hash of our latest block
266
- # latest_hash = self.latest_block.get_hash()
237
+ # Get the hash of our latest block
238
+ latest_hash = self.latest_block.get_hash()
267
239
 
268
- # # Find any pending blocks that build on our latest block
269
- # main_chain_blocks = []
270
- # for block_hash, data in list(self.pending_blocks.items()):
271
- # block = data['block']
240
+ # Find any pending blocks that build on our latest block
241
+ main_chain_blocks = []
242
+ for block_hash, data in list(self.pending_blocks.items()):
243
+ block = data['block']
272
244
 
273
- # # Check if this block extends our latest block
274
- # if block.previous == latest_hash:
275
- # main_chain_blocks.append(block)
245
+ # Check if this block extends our latest block
246
+ if block.previous == latest_hash:
247
+ main_chain_blocks.append(block)
276
248
 
277
- # # Process found blocks
278
- # for block in main_chain_blocks:
279
- # self._validate_and_process_main_chain_block(block)
249
+ # Process found blocks
250
+ for block in main_chain_blocks:
251
+ self._validate_and_process_main_chain_block(block)
280
252
 
281
- # def _validate_and_process_main_chain_block(self, block: Block):
282
- # """
283
- # Validate and process a block that extends our main chain.
284
-
285
- # Args:
286
- # block: Block to validate and process
287
- # """
288
- # try:
289
- # # Validate block
290
- # is_valid = validate_block(block, self.blockchain.get_accounts_at_block(block.previous), self.blockchain.get_blocks())
253
+ def _validate_and_process_main_chain_block(self, block: Block):
254
+ """
255
+ Validate and process a block that extends our main chain.
256
+
257
+ Args:
258
+ block: Block to validate and process
259
+ """
260
+ try:
261
+ # Validate block
262
+ is_valid = validate_block(block, self.blockchain.get_accounts_at_block(block.previous), self.blockchain.get_blocks())
291
263
 
292
- # if is_valid:
293
- # # Apply block to our state
294
- # success = validate_and_apply_block(self.blockchain, block)
295
- # if success:
296
- # print(f"Applied valid block {block.number} to blockchain state")
297
- # self._update_latest_block(block)
298
- # blocks_to_remove = [block.get_hash()]
299
- # for block_hash in blocks_to_remove:
300
- # if block_hash in self.pending_blocks:
301
- # del self.pending_blocks[block_hash]
302
- # print(f"Added block {block.number} to blockchain")
303
- # return True
304
- # except Exception as e:
305
- # print(f"Error validating main chain block {block.number}: {e}")
264
+ if is_valid:
265
+ # Apply block to our state
266
+ success = validate_and_apply_block(self.blockchain, block)
267
+ if success:
268
+ print(f"Applied valid block {block.number} to blockchain state")
269
+ self._update_latest_block(block)
270
+ blocks_to_remove = [block.get_hash()]
271
+ for block_hash in blocks_to_remove:
272
+ if block_hash in self.pending_blocks:
273
+ del self.pending_blocks[block_hash]
274
+ print(f"Added block {block.number} to blockchain")
275
+ return True
276
+ except Exception as e:
277
+ print(f"Error validating main chain block {block.number}: {e}")
306
278
 
307
- # return False
279
+ return False
308
280
 
309
- # def _evaluate_candidate_chains(self):
310
- # """
311
- # Evaluate candidate chains to determine if any should become our main chain.
312
- # This will validate pending blocks and look for chains with higher cumulative difficulty.
313
- # """
314
- # # Skip if no candidate chains
315
- # if not self.candidate_chains:
316
- # return
281
+ def _evaluate_candidate_chains(self):
282
+ """
283
+ Evaluate candidate chains to determine if any should become our main chain.
284
+ This will validate pending blocks and look for chains with higher cumulative difficulty.
285
+ """
286
+ # Skip if no candidate chains
287
+ if not self.candidate_chains:
288
+ return
317
289
 
318
- # # For each candidate chain, validate blocks and calculate metrics
319
- # for chain_id, data in list(self.candidate_chains.items()):
320
- # latest_candidate_block = data['latest_block']
290
+ # For each candidate chain, validate blocks and calculate metrics
291
+ for chain_id, data in list(self.candidate_chains.items()):
292
+ latest_candidate_block = data['latest_block']
321
293
 
322
- # # Build the chain backwards
323
- # chain_blocks = self._build_chain_from_latest(latest_candidate_block)
294
+ # Build the chain backwards
295
+ chain_blocks = self._build_chain_from_latest(latest_candidate_block)
324
296
 
325
- # # Skip if we couldn't build a complete chain
326
- # if not chain_blocks:
327
- # continue
297
+ # Skip if we couldn't build a complete chain
298
+ if not chain_blocks:
299
+ continue
328
300
 
329
- # # Validate the entire chain
330
- # valid_chain = self._validate_candidate_chain(chain_blocks)
301
+ # Validate the entire chain
302
+ valid_chain = self._validate_candidate_chain(chain_blocks)
331
303
 
332
- # # If valid and better than our current chain, switch to it
333
- # if valid_chain and self._is_better_chain(chain_blocks):
334
- # self._switch_to_new_chain(chain_blocks)
304
+ # If valid and better than our current chain, switch to it
305
+ if valid_chain and self._is_better_chain(chain_blocks):
306
+ self._switch_to_new_chain(chain_blocks)
335
307
 
336
- # def _build_chain_from_latest(self, latest_block: Block) -> List[Block]:
337
- # """
338
- # Build a chain from the latest block back to a known point in our blockchain.
308
+ def _build_chain_from_latest(self, latest_block: Block) -> List[Block]:
309
+ """
310
+ Build a chain from the latest block back to a known point in our blockchain.
339
311
 
340
- # Args:
341
- # latest_block: Latest block in the candidate chain
312
+ Args:
313
+ latest_block: Latest block in the candidate chain
342
314
 
343
- # Returns:
344
- # List of blocks in the chain, ordered from oldest to newest
345
- # """
346
- # chain_blocks = [latest_block]
347
- # current_block = latest_block
348
-
349
- # # Track visited blocks to avoid cycles
350
- # visited = {current_block.get_hash()}
351
-
352
- # # Build chain backwards until we either:
353
- # # 1. Find a block in our main chain
354
- # # 2. Run out of blocks
355
- # # 3. Detect a cycle
356
- # while current_block.number > 0:
357
- # previous_hash = current_block.previous
315
+ Returns:
316
+ List of blocks in the chain, ordered from oldest to newest
317
+ """
318
+ chain_blocks = [latest_block]
319
+ current_block = latest_block
320
+
321
+ # Track visited blocks to avoid cycles
322
+ visited = {current_block.get_hash()}
323
+
324
+ # Build chain backwards until we either:
325
+ # 1. Find a block in our main chain
326
+ # 2. Run out of blocks
327
+ # 3. Detect a cycle
328
+ while current_block.number > 0:
329
+ previous_hash = current_block.previous
358
330
 
359
- # # Check if we have this block in our blockchain
360
- # if hasattr(self.blockchain, 'has_block') and self.blockchain.has_block(previous_hash):
361
- # # Found connection to our main chain
362
- # previous_block = self.blockchain.get_block(previous_hash)
363
- # chain_blocks.insert(0, previous_block)
364
- # break
331
+ # Check if we have this block in our blockchain
332
+ if hasattr(self.blockchain, 'has_block') and self.blockchain.has_block(previous_hash):
333
+ # Found connection to our main chain
334
+ previous_block = self.blockchain.get_block(previous_hash)
335
+ chain_blocks.insert(0, previous_block)
336
+ break
365
337
 
366
- # # Check if block is in pending blocks
367
- # elif previous_hash in self.pending_blocks:
368
- # previous_block = self.pending_blocks[previous_hash]['block']
338
+ # Check if block is in pending blocks
339
+ elif previous_hash in self.pending_blocks:
340
+ previous_block = self.pending_blocks[previous_hash]['block']
369
341
 
370
- # # Check for cycles
371
- # if previous_hash in visited:
372
- # print(f"Cycle detected in candidate chain at block {previous_block.number}")
373
- # return []
342
+ # Check for cycles
343
+ if previous_hash in visited:
344
+ print(f"Cycle detected in candidate chain at block {previous_block.number}")
345
+ return []
374
346
 
375
- # visited.add(previous_hash)
376
- # chain_blocks.insert(0, previous_block)
377
- # current_block = previous_block
378
- # else:
379
- # # Missing block, cannot validate the chain
380
- # print(f"Missing block {previous_hash.hex()} in candidate chain")
381
- # return []
347
+ visited.add(previous_hash)
348
+ chain_blocks.insert(0, previous_block)
349
+ current_block = previous_block
350
+ else:
351
+ # Missing block, cannot validate the chain
352
+ print(f"Missing block {previous_hash.hex()} in candidate chain")
353
+ return []
382
354
 
383
- # return chain_blocks
355
+ return chain_blocks
384
356
 
385
- # def _validate_candidate_chain(self, chain_blocks: List[Block]) -> bool:
386
- # """
387
- # Validate a candidate chain of blocks.
357
+ def _validate_candidate_chain(self, chain_blocks: List[Block]) -> bool:
358
+ """
359
+ Validate a candidate chain of blocks.
388
360
 
389
- # Args:
390
- # chain_blocks: List of blocks in the chain (oldest to newest)
361
+ Args:
362
+ chain_blocks: List of blocks in the chain (oldest to newest)
391
363
 
392
- # Returns:
393
- # True if the chain is valid, False otherwise
394
- # """
395
- # # Validate each block in the chain
396
- # for i, block in enumerate(chain_blocks):
397
- # # Skip first block, it's either genesis or a block we already have
398
- # if i == 0:
399
- # continue
364
+ Returns:
365
+ True if the chain is valid, False otherwise
366
+ """
367
+ # Validate each block in the chain
368
+ for i, block in enumerate(chain_blocks):
369
+ # Skip first block, it's either genesis or a block we already have
370
+ if i == 0:
371
+ continue
400
372
 
401
- # # Validate block connections
402
- # if block.previous != chain_blocks[i-1].get_hash():
403
- # print(f"Invalid chain: block {block.number} does not reference previous block")
404
- # return False
373
+ # Validate block connections
374
+ if block.previous != chain_blocks[i-1].get_hash():
375
+ print(f"Invalid chain: block {block.number} does not reference previous block")
376
+ return False
405
377
 
406
- # # Validate block
407
- # is_valid = validate_block(block, self.blockchain.get_accounts_at_block(block.previous), self.blockchain.get_blocks())
408
- # if not is_valid:
409
- # print(f"Invalid chain: block {block.number} is invalid")
410
- # return False
378
+ # Validate block
379
+ is_valid = validate_block(block, self.blockchain.get_accounts_at_block(block.previous), self.blockchain.get_blocks())
380
+ if not is_valid:
381
+ print(f"Invalid chain: block {block.number} is invalid")
382
+ return False
411
383
 
412
- # return True
384
+ return True
413
385
 
414
- # def _is_better_chain(self, chain_blocks: List[Block]) -> bool:
415
- # """
416
- # Determine if a candidate chain is better than our current chain.
386
+ def _is_better_chain(self, chain_blocks: List[Block]) -> bool:
387
+ """
388
+ Determine if a candidate chain is better than our current chain.
417
389
 
418
- # Args:
419
- # chain_blocks: List of blocks in the candidate chain
390
+ Args:
391
+ chain_blocks: List of blocks in the candidate chain
420
392
 
421
- # Returns:
422
- # True if the candidate chain is better, False otherwise
423
- # """
424
- # # Get the latest block from the candidate chain
425
- # candidate_latest = chain_blocks[-1]
426
-
427
- # # If we don't have a latest block, any valid chain is better
428
- # if not self.latest_block:
429
- # return True
393
+ Returns:
394
+ True if the candidate chain is better, False otherwise
395
+ """
396
+ # Get the latest block from the candidate chain
397
+ candidate_latest = chain_blocks[-1]
398
+
399
+ # If we don't have a latest block, any valid chain is better
400
+ if not self.latest_block:
401
+ return True
430
402
 
431
- # # Compare block numbers (longest chain rule)
432
- # if candidate_latest.number > self.latest_block.number:
433
- # print(f"Candidate chain is longer: {candidate_latest.number} vs {self.latest_block.number}")
434
- # return True
403
+ # Compare block numbers (longest chain rule)
404
+ if candidate_latest.number > self.latest_block.number:
405
+ print(f"Candidate chain is longer: {candidate_latest.number} vs {self.latest_block.number}")
406
+ return True
435
407
 
436
- # return False
437
-
438
- # def _switch_to_new_chain(self, chain_blocks: List[Block]):
439
- # """
440
- # Switch to a new chain by adding all blocks to our blockchain.
441
-
442
- # Args:
443
- # chain_blocks: List of blocks in the chain (oldest to newest)
444
- # """
445
- # # Find the point where the chains diverge
446
- # divergence_point = 0
447
- # for i, block in enumerate(chain_blocks):
448
- # # Check if we have this block in our blockchain
449
- # if hasattr(self.blockchain, 'has_block') and self.blockchain.has_block(block.get_hash()):
450
- # divergence_point = i + 1
451
- # else:
452
- # break
408
+ return False
409
+
410
+ def _switch_to_new_chain(self, chain_blocks: List[Block]):
411
+ """
412
+ Switch to a new chain by adding all blocks to our blockchain.
413
+
414
+ Args:
415
+ chain_blocks: List of blocks in the chain (oldest to newest)
416
+ """
417
+ # Find the point where the chains diverge
418
+ divergence_point = 0
419
+ for i, block in enumerate(chain_blocks):
420
+ # Check if we have this block in our blockchain
421
+ if hasattr(self.blockchain, 'has_block') and self.blockchain.has_block(block.get_hash()):
422
+ divergence_point = i + 1
423
+ else:
424
+ break
453
425
 
454
- # # Add all blocks after the divergence point
455
- # for i in range(divergence_point, len(chain_blocks)):
456
- # block = chain_blocks[i]
426
+ # Add all blocks after the divergence point
427
+ for i in range(divergence_point, len(chain_blocks)):
428
+ block = chain_blocks[i]
457
429
 
458
- # # Add block to blockchain
459
- # if hasattr(self.blockchain, 'add_block'):
460
- # try:
461
- # self.blockchain.add_block(block)
430
+ # Add block to blockchain
431
+ if hasattr(self.blockchain, 'add_block'):
432
+ try:
433
+ self.blockchain.add_block(block)
462
434
 
463
- # # Remove from pending blocks
464
- # block_hash = block.get_hash()
465
- # if block_hash in self.pending_blocks:
466
- # del self.pending_blocks[block_hash]
435
+ # Remove from pending blocks
436
+ block_hash = block.get_hash()
437
+ if block_hash in self.pending_blocks:
438
+ del self.pending_blocks[block_hash]
467
439
 
468
- # print(f"Added block {block.number} to blockchain")
469
- # except Exception as e:
470
- # print(f"Error adding block {block.number} to blockchain: {e}")
471
- # return
440
+ print(f"Added block {block.number} to blockchain")
441
+ except Exception as e:
442
+ print(f"Error adding block {block.number} to blockchain: {e}")
443
+ return
472
444
 
473
- # # Update latest block
474
- # self._update_latest_block(chain_blocks[-1])
475
- # print(f"Switched to new chain, latest block: {self.latest_block.number}")
445
+ # Update latest block
446
+ self._update_latest_block(chain_blocks[-1])
447
+ print(f"Switched to new chain, latest block: {self.latest_block.number}")
@@ -1,84 +0,0 @@
1
- """
2
- Validation module for the Astreum blockchain.
3
-
4
- This module provides functions for validating blocks and transactions,
5
- computing and verifying VDFs, and selecting validators.
6
- """
7
-
8
- # Export validation functions
9
- from .block import (
10
- validate_block,
11
- create_block,
12
- create_genesis_block,
13
- select_validator,
14
- select_validator_for_slot
15
- )
16
-
17
- # Export VDF functions
18
- from .vdf import (
19
- compute_vdf,
20
- verify_vdf,
21
- validate_block_vdf
22
- )
23
-
24
- # Export account functions
25
- from .account import (
26
- Account,
27
- get_validator_stake,
28
- is_validator
29
- )
30
-
31
- # Export constants
32
- from .constants import (
33
- VALIDATION_ADDRESS,
34
- BURN_ADDRESS,
35
- MIN_STAKE_AMOUNT,
36
- SLOT_DURATION,
37
- VDF_DIFFICULTY
38
- )
39
-
40
- # Export blockchain state functions
41
- from .state import (
42
- add_block_to_state,
43
- validate_and_apply_block,
44
- create_account_state,
45
- get_validator_for_slot,
46
- select_best_chain,
47
- compare_chains,
48
- get_validator_set
49
- )
50
-
51
- __all__ = [
52
- # Block validation
53
- 'validate_block',
54
- 'create_block',
55
- 'create_genesis_block',
56
- 'select_validator',
57
- 'select_validator_for_slot',
58
-
59
- # VDF functions
60
- 'compute_vdf',
61
- 'verify_vdf',
62
- 'validate_block_vdf',
63
-
64
- # Account functions
65
- 'Account',
66
- 'get_validator_stake',
67
- 'is_validator',
68
-
69
- # Constants
70
- 'VALIDATION_ADDRESS',
71
- 'BURN_ADDRESS',
72
- 'MIN_STAKE_AMOUNT',
73
- 'SLOT_DURATION',
74
- 'VDF_DIFFICULTY',
75
-
76
- # Blockchain state
77
- 'add_block_to_state',
78
- 'validate_and_apply_block',
79
- 'create_account_state',
80
- 'get_validator_for_slot',
81
- 'select_best_chain',
82
- 'compare_chains',
83
- 'get_validator_set'
84
- ]
@@ -1,12 +0,0 @@
1
- """
2
- Block validation module for the Astreum blockchain.
3
- """
4
-
5
- from .model import Block
6
- from .create import create_block, create_genesis_block
7
-
8
- __all__ = [
9
- 'Block',
10
- 'create_block',
11
- 'create_genesis_block',
12
- ]
@@ -1,29 +1,20 @@
1
1
  class Block:
2
+
3
+ def __init__(self):
4
+ pass
5
+
2
6
  @classmethod
3
- def from_bytes(cls, validator) -> 'Block':
7
+ def from_bytes(cls) -> 'Block':
4
8
  """
5
- Deserialize an Account from its byte representation.
6
-
7
- Expected format: [balance, code, counter, data]
8
-
9
- The public_key (and optional secret_key) must be provided separately.
9
+ Deserialize a block from its byte representation.
10
10
  """
11
- decoded = bytes_format.decode(data)
12
- balance, code, counter, account_data = decoded
13
- return cls(public_key, balance, code, counter, account_data, secret_key=secret_key)
14
-
11
+ return cls()
12
+
15
13
  def to_bytes(self) -> bytes:
16
14
  """
17
- Serialize the Account into bytes.
18
-
19
- Format: [balance, code, counter, data]
15
+ Serialize the block into bytes.
20
16
  """
21
- return bytes_format.encode([
22
- self.balance,
23
- self.code,
24
- self.counter,
25
- self.data
26
- ])
17
+ return b""
27
18
 
28
19
  class Chain:
29
20
  def __init__(self, latest_block: Block):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astreum
3
- Version: 0.1.18
3
+ Version: 0.1.19
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
@@ -21,7 +21,7 @@ astreum/lispeum/special/number/addition.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
21
21
  astreum/machine/__init__.py,sha256=GOdZl1tS9uIJHbq5WVcplifMDPDLQroX7CVew-K2YbA,15262
22
22
  astreum/machine/environment.py,sha256=K0084U6B7wwjrDZ9b2_7cEcbBzsB7UOy_Zpbrr7B3GY,834
23
23
  astreum/machine/error.py,sha256=MvqBaZZt33rNELNhUJ2lER3TE3aS8WVqsWF2hz2AwoA,38
24
- astreum/node/__init__.py,sha256=zY4rD4knr8zPOmXX3eL-VENCQ-SGDccUQlTLEzzQaAA,20073
24
+ astreum/node/__init__.py,sha256=obb-ap7YuRrMblNN7IAK79xEq__9aNBVzt1ciSTMvoU,18631
25
25
  astreum/node/utils.py,sha256=amGhNYHVMjvAO-9vBRAcim-S5LlLSRudqooBN-XPdm4,702
26
26
  astreum/node/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
27
  astreum/node/crypto/ed25519.py,sha256=FRnvlN0kZlxn4j-sJKl-C9tqiz_0z4LZyXLj3KIj1TQ,1760
@@ -37,22 +37,21 @@ astreum/node/storage/merkle.py,sha256=sC7gfxPDUBgv3iiFs5PyxPgYbC4CoE-If5TQvkuoTG
37
37
  astreum/node/storage/patricia.py,sha256=zP4whShdB7yOFcEPLE1-1PIFfx_LdK8DyMSadnF0KT0,11588
38
38
  astreum/node/storage/storage.py,sha256=czJDhRK2rQxjOo88fhZ6j10f55RW8hWp1qq7c4yur6Y,10086
39
39
  astreum/node/storage/utils.py,sha256=CxKH9GbW31aVYs2Hwg1SirCykSnH_3_JisEayDrpOvY,5169
40
- astreum/node/validation/__init__.py,sha256=D9Gmc5x5V5xgXtM32axuDMSzgKiDCz7MiUShNnuFKYc,1636
40
+ astreum/node/validation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  astreum/node/validation/account.py,sha256=mKbJSi3sfQ5K9a4zwgdyPGqT3gXHekI55yDDVpzcolo,3650
42
- astreum/node/validation/block.py,sha256=ff4ZvMtIBuoY232SHxtRiwU3J-ku_hQOiqssHhIqbXY,934
42
+ astreum/node/validation/block.py,sha256=KRvlpLZOmgJ3WJaSHsbk7ryh2Z1NsC2z-RWKWh1quBE,444
43
43
  astreum/node/validation/constants.py,sha256=ImIdLZFtMKx1iWg60YssEKl2tdDqZQnIa2JaJE6CX0o,422
44
44
  astreum/node/validation/stake.py,sha256=Z9EPM-X9c92fpsZIYsdVpvgz4DhxQViPM-RDktWUZq8,7141
45
- astreum/node/validation/state.py,sha256=QMXY7h4da-o79wMjJW93ixtepyhgcbJEf101yVuZurg,7661
46
45
  astreum/node/validation/transaction.py,sha256=Lovx1CWIxL45glFU-LBDxI1argBLxSmDAcg1TteaOlY,4701
47
46
  astreum/node/validation/vdf.py,sha256=HDdnqn9O_LicfE7SNCmncawKoR-ojLyjlpn74OvRNOU,2194
48
- astreum/node/validation/_block/__init__.py,sha256=n2HaMG_5cpa7y5xko-c7vbHz8rL-1wAGthmr8boNrCs,216
47
+ astreum/node/validation/_block/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
48
  astreum/node/validation/_block/create.py,sha256=apD9h92b9Y146zeppSzKNk_NJPgyBy7FhxoEkypQQNk,2515
50
49
  astreum/node/validation/_block/model.py,sha256=d7x3_tX2MPLnGODL_5_vNjQfLdYa405blc-zL9o8HFA,2589
51
50
  astreum/node/validation/_block/validate.py,sha256=niLexCNhEwUJLclyrdNZSvHcVa_J6jlu7J3FiWY7XBU,6232
52
51
  astreum/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
52
  astreum/utils/bytes_format.py,sha256=X4tG5GGPweNCE54bHYkLFiuLTbmpy5upO_s1Cef-MGA,2711
54
- astreum-0.1.18.dist-info/licenses/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
55
- astreum-0.1.18.dist-info/METADATA,sha256=k1Eptg-mbsR5Ddo2ky6JCIgkKlXO0WqovKe5zKDSZ3c,3312
56
- astreum-0.1.18.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
57
- astreum-0.1.18.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
58
- astreum-0.1.18.dist-info/RECORD,,
53
+ astreum-0.1.19.dist-info/licenses/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
54
+ astreum-0.1.19.dist-info/METADATA,sha256=MvTCByomvRA9Tf_iCyOyxeGCsSnNyHSrtoRChhbx0ls,3312
55
+ astreum-0.1.19.dist-info/WHEEL,sha256=wXxTzcEDnjrTwFYjLPcsW_7_XihufBwmpiBeiXNBGEA,91
56
+ astreum-0.1.19.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
57
+ astreum-0.1.19.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (79.0.1)
2
+ Generator: setuptools (80.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,230 +0,0 @@
1
- """
2
- Blockchain state management.
3
-
4
- This module manages the blockchain state, including accounts, blocks, and
5
- transactions.
6
- """
7
-
8
- import time
9
- from typing import Dict, List, Optional, Set, Any
10
- from dataclasses import dataclass, field
11
- from ..utils import hash_data
12
- from ..models import Block, Transaction, Account as ModelAccount
13
- from .account import Account
14
- from .constants import VALIDATION_ADDRESS, BURN_ADDRESS, MIN_STAKE_AMOUNT
15
-
16
-
17
- class BlockchainState:
18
- """
19
- Manages the state of the blockchain.
20
-
21
- This class tracks the current state of accounts, blocks, and transactions,
22
- and provides methods to update the state with new blocks and transactions.
23
- """
24
-
25
- def __init__(self, config: Optional[dict] = None):
26
- """
27
- Initialize blockchain state.
28
-
29
- Args:
30
- config: Optional configuration
31
- """
32
- self.config = config or {}
33
-
34
- # Dictionaries to track blockchain state
35
- self.accounts = {} # address -> Account
36
- self.blocks = {} # hash -> Block
37
- self.transactions = {} # hash -> Transaction
38
-
39
- # Track the latest block
40
- self.latest_block = None
41
-
42
- # Pending transactions
43
- self.pending_transactions = set() # Set of transaction hashes
44
-
45
- # State of validators and stakes
46
- self.validators = {} # address -> stake amount
47
-
48
- # Initialize the genesis block if not provided
49
- if not self.latest_block:
50
- self._initialize_genesis()
51
-
52
- def _initialize_genesis(self):
53
- """Initialize the genesis block and state."""
54
- # In a full implementation, this would initialize the genesis
55
- # block and state from configuration
56
- print("Initializing genesis block and state")
57
-
58
- def add_block(self, block: Block) -> bool:
59
- """
60
- Add a block to the blockchain state.
61
-
62
- Args:
63
- block: Block to add
64
-
65
- Returns:
66
- True if block was added successfully, False otherwise
67
- """
68
- # Convert block to validation format directly
69
- validation_block = {
70
- 'number': block.number,
71
- 'timestamp': block.time,
72
- 'producer': block.validator.public_key if block.validator else b'',
73
- 'previous': block.previous.get_hash() if block.previous else b'',
74
- 'transactions': self._extract_transactions(block),
75
- 'vdf_proof': block.signature[:8], # Use part of signature as VDF proof for demo
76
- 'signature': block.signature
77
- }
78
-
79
- # Check for duplicate (already processed) blocks
80
- block_hash = block.get_hash()
81
- if block_hash in self.blocks:
82
- print(f"Block {block_hash.hex()} already in blockchain")
83
- return True
84
-
85
- # Convert block's accounts to validation accounts
86
- account_dict = {}
87
- # Here we would deserialize the accounts data from the block
88
- # In a real implementation, this would reconstruct accounts from serialized data
89
-
90
- # For now, we'll just log that we would process the block
91
- print(f"Processing block at height {block.number}")
92
-
93
- # Add the block to our state
94
- self.blocks[block_hash] = block
95
-
96
- # Update latest block if this is a new latest block
97
- if not self.latest_block or block.number > self.latest_block.number:
98
- self.latest_block = block
99
-
100
- # Process transactions in the block
101
- # This would update account states, apply transaction effects, etc.
102
-
103
- return True
104
-
105
- def _extract_transactions(self, block: Block) -> List[dict]:
106
- """
107
- Extract transactions from a block.
108
-
109
- Args:
110
- block: The model Block instance
111
-
112
- Returns:
113
- List of transactions in validation format
114
- """
115
- transactions = []
116
- # Parse transaction data from the block
117
- # In a real implementation, this would deserialize the transactions field
118
- # For now, we'll return an empty list as a placeholder
119
- return transactions
120
-
121
- def add_transaction(self, transaction: Transaction) -> bool:
122
- """
123
- Add a transaction to the pending set.
124
-
125
- Args:
126
- transaction: Transaction to add
127
-
128
- Returns:
129
- True if transaction was added successfully, False otherwise
130
- """
131
- # Convert transaction to validation format directly
132
- validation_tx = {
133
- 'sender': transaction.sender.public_key if transaction.sender else b'',
134
- 'recipient': transaction.receipient.public_key if transaction.receipient else b'',
135
- 'amount': transaction.amount,
136
- 'counter': transaction.counter,
137
- 'data': transaction.data,
138
- 'signature': transaction.signature
139
- }
140
-
141
- # Generate a transaction hash
142
- tx_hash = hash_data(str(validation_tx).encode())
143
-
144
- # Check for duplicate transactions
145
- if tx_hash in self.transactions or tx_hash in self.pending_transactions:
146
- print(f"Transaction {tx_hash.hex()} already processed or pending")
147
- return False
148
-
149
- # Validate the transaction
150
- # In a real implementation, this would check signature, sender balance, etc.
151
-
152
- # Add to pending transactions
153
- self.pending_transactions.add(tx_hash)
154
-
155
- return True
156
-
157
- def is_staking_transaction(self, tx: Transaction) -> bool:
158
- """
159
- Check if a transaction is a staking transaction.
160
-
161
- Args:
162
- tx: The model Transaction instance
163
-
164
- Returns:
165
- True if this is a staking transaction, False otherwise
166
- """
167
- # A transaction is a staking transaction if it's sending to the validation address
168
- if tx.receipient and hasattr(tx.receipient, 'public_key'):
169
- return tx.receipient.public_key == VALIDATION_ADDRESS
170
- return False
171
-
172
- def get_account(self, address: bytes) -> Optional[Account]:
173
- """
174
- Get an account by address.
175
-
176
- Args:
177
- address: Account address
178
-
179
- Returns:
180
- Account if found, None otherwise
181
- """
182
- return self.accounts.get(address)
183
-
184
- def get_validator_stake(self, address: bytes) -> int:
185
- """
186
- Get the stake of a validator.
187
-
188
- Args:
189
- address: Validator address
190
-
191
- Returns:
192
- Stake amount (0 if not a validator)
193
- """
194
- return self.validators.get(address, 0)
195
-
196
- def is_validator(self, address: bytes) -> bool:
197
- """
198
- Check if an address is a validator.
199
-
200
- Args:
201
- address: Address to check
202
-
203
- Returns:
204
- True if address is a validator, False otherwise
205
- """
206
- return self.get_validator_stake(address) >= MIN_STAKE_AMOUNT
207
-
208
- def get_pending_transactions(self) -> List[Transaction]:
209
- """
210
- Get all pending transactions.
211
-
212
- Returns:
213
- List of pending transactions
214
- """
215
- # In a real implementation, this would return the actual transaction objects
216
- # For now, we'll just return an empty list
217
- return []
218
-
219
-
220
- def create_blockchain(config: Optional[dict] = None) -> BlockchainState:
221
- """
222
- Create a new blockchain state.
223
-
224
- Args:
225
- config: Optional configuration
226
-
227
- Returns:
228
- New BlockchainState instance
229
- """
230
- return BlockchainState(config)