astreum 0.1.18__py3-none-any.whl → 0.1.20__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 +390 -418
- astreum/node/storage/__init__.py +0 -13
- astreum/node/storage/merkle.py +65 -65
- astreum/node/validation/__init__.py +0 -84
- astreum/node/validation/_block/__init__.py +0 -12
- astreum/node/validation/block.py +10 -19
- {astreum-0.1.18.dist-info → astreum-0.1.20.dist-info}/METADATA +1 -1
- {astreum-0.1.18.dist-info → astreum-0.1.20.dist-info}/RECORD +11 -12
- {astreum-0.1.18.dist-info → astreum-0.1.20.dist-info}/WHEEL +1 -1
- astreum/node/validation/state.py +0 -230
- {astreum-0.1.18.dist-info → astreum-0.1.20.dist-info}/licenses/LICENSE +0 -0
- {astreum-0.1.18.dist-info → astreum-0.1.20.dist-info}/top_level.txt +0 -0
astreum/node/storage/__init__.py
CHANGED
|
@@ -1,13 +0,0 @@
|
|
|
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
|
-
]
|
astreum/node/storage/merkle.py
CHANGED
|
@@ -1,7 +1,71 @@
|
|
|
1
1
|
import blake3
|
|
2
2
|
from .storage import Storage
|
|
3
|
-
|
|
3
|
+
from astreum.utils import bytes_format
|
|
4
4
|
|
|
5
|
+
class MerkleNode:
|
|
6
|
+
def __init__(self, leaf: bool, data: bytes):
|
|
7
|
+
"""
|
|
8
|
+
Initialize a Merkle node.
|
|
9
|
+
|
|
10
|
+
For a leaf node, `data` is the actual content to be stored.
|
|
11
|
+
For an internal node, `data` should be the concatenation of the two child hashes.
|
|
12
|
+
|
|
13
|
+
:param leaf: A boolean flag indicating whether this node is a leaf node (True) or an internal node (False).
|
|
14
|
+
:param data: The node's data. For leaves, the stored data; for internal nodes, concatenated child hashes.
|
|
15
|
+
"""
|
|
16
|
+
self.leaf = leaf
|
|
17
|
+
self.data = data
|
|
18
|
+
self._hash = None # Cached hash value to avoid recomputation.
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_bytes(cls, data: bytes) -> 'MerkleNode':
|
|
22
|
+
"""
|
|
23
|
+
Deserialize a MerkleNode from its byte representation.
|
|
24
|
+
|
|
25
|
+
The input bytes are expected to be in the Astreum format, containing a leaf flag and node data.
|
|
26
|
+
|
|
27
|
+
:param data: The serialized node data.
|
|
28
|
+
:return: A new MerkleNode instance.
|
|
29
|
+
"""
|
|
30
|
+
leaf_flag, node_data = bytes_format.decode(data)
|
|
31
|
+
return cls(True if leaf_flag == 1 else False, node_data)
|
|
32
|
+
|
|
33
|
+
@classmethod
|
|
34
|
+
def from_storage(cls, storage: Storage, hash_value: bytes) -> 'MerkleNode' or None:
|
|
35
|
+
"""
|
|
36
|
+
Retrieve and deserialize a MerkleNode from storage using its hash.
|
|
37
|
+
|
|
38
|
+
:param storage: The Storage instance used to retrieve the node.
|
|
39
|
+
:param hash_value: The hash key under which the node is stored.
|
|
40
|
+
:return: A MerkleNode instance if found, otherwise None.
|
|
41
|
+
"""
|
|
42
|
+
node_bytes = storage.get(hash_value)
|
|
43
|
+
if node_bytes is None:
|
|
44
|
+
return None
|
|
45
|
+
return cls.from_bytes(node_bytes)
|
|
46
|
+
|
|
47
|
+
def to_bytes(self) -> bytes:
|
|
48
|
+
"""
|
|
49
|
+
Serialize the MerkleNode into bytes using the Astreum format.
|
|
50
|
+
|
|
51
|
+
The format encodes a list containing the leaf flag and the node data.
|
|
52
|
+
|
|
53
|
+
:return: The serialized bytes representing the node.
|
|
54
|
+
"""
|
|
55
|
+
return bytes_format.encode([1 if self.leaf else 0, self.data])
|
|
56
|
+
|
|
57
|
+
def hash(self) -> bytes:
|
|
58
|
+
"""
|
|
59
|
+
Compute (or retrieve a cached) hash of the node using the Blake3 algorithm.
|
|
60
|
+
|
|
61
|
+
For leaf nodes, the hash is computed over the actual data.
|
|
62
|
+
For internal nodes, the hash is computed over the concatenated child hashes.
|
|
63
|
+
|
|
64
|
+
:return: The Blake3 digest of the node's data.
|
|
65
|
+
"""
|
|
66
|
+
if self._hash is None:
|
|
67
|
+
self._hash = blake3.blake3(self.data).digest()
|
|
68
|
+
return self._hash
|
|
5
69
|
|
|
6
70
|
|
|
7
71
|
class MerkleTree:
|
|
@@ -158,67 +222,3 @@ class MerkleTree:
|
|
|
158
222
|
return new_node_hash
|
|
159
223
|
|
|
160
224
|
|
|
161
|
-
class MerkleNode:
|
|
162
|
-
def __init__(self, leaf: bool, data: bytes):
|
|
163
|
-
"""
|
|
164
|
-
Initialize a Merkle node.
|
|
165
|
-
|
|
166
|
-
For a leaf node, `data` is the actual content to be stored.
|
|
167
|
-
For an internal node, `data` should be the concatenation of the two child hashes.
|
|
168
|
-
|
|
169
|
-
:param leaf: A boolean flag indicating whether this node is a leaf node (True) or an internal node (False).
|
|
170
|
-
:param data: The node's data. For leaves, the stored data; for internal nodes, concatenated child hashes.
|
|
171
|
-
"""
|
|
172
|
-
self.leaf = leaf
|
|
173
|
-
self.data = data
|
|
174
|
-
self._hash = None # Cached hash value to avoid recomputation.
|
|
175
|
-
|
|
176
|
-
@classmethod
|
|
177
|
-
def from_bytes(cls, data: bytes) -> 'MerkleNode':
|
|
178
|
-
"""
|
|
179
|
-
Deserialize a MerkleNode from its byte representation.
|
|
180
|
-
|
|
181
|
-
The input bytes are expected to be in the Astreum format, containing a leaf flag and node data.
|
|
182
|
-
|
|
183
|
-
:param data: The serialized node data.
|
|
184
|
-
:return: A new MerkleNode instance.
|
|
185
|
-
"""
|
|
186
|
-
leaf_flag, node_data = bytes_format.decode(data)
|
|
187
|
-
return cls(True if leaf_flag == 1 else False, node_data)
|
|
188
|
-
|
|
189
|
-
@classmethod
|
|
190
|
-
def from_storage(cls, storage: Storage, hash_value: bytes) -> 'MerkleNode' or None:
|
|
191
|
-
"""
|
|
192
|
-
Retrieve and deserialize a MerkleNode from storage using its hash.
|
|
193
|
-
|
|
194
|
-
:param storage: The Storage instance used to retrieve the node.
|
|
195
|
-
:param hash_value: The hash key under which the node is stored.
|
|
196
|
-
:return: A MerkleNode instance if found, otherwise None.
|
|
197
|
-
"""
|
|
198
|
-
node_bytes = storage.get(hash_value)
|
|
199
|
-
if node_bytes is None:
|
|
200
|
-
return None
|
|
201
|
-
return cls.from_bytes(node_bytes)
|
|
202
|
-
|
|
203
|
-
def to_bytes(self) -> bytes:
|
|
204
|
-
"""
|
|
205
|
-
Serialize the MerkleNode into bytes using the Astreum format.
|
|
206
|
-
|
|
207
|
-
The format encodes a list containing the leaf flag and the node data.
|
|
208
|
-
|
|
209
|
-
:return: The serialized bytes representing the node.
|
|
210
|
-
"""
|
|
211
|
-
return bytes_format.encode([1 if self.leaf else 0, self.data])
|
|
212
|
-
|
|
213
|
-
def hash(self) -> bytes:
|
|
214
|
-
"""
|
|
215
|
-
Compute (or retrieve a cached) hash of the node using the Blake3 algorithm.
|
|
216
|
-
|
|
217
|
-
For leaf nodes, the hash is computed over the actual data.
|
|
218
|
-
For internal nodes, the hash is computed over the concatenated child hashes.
|
|
219
|
-
|
|
220
|
-
:return: The Blake3 digest of the node's data.
|
|
221
|
-
"""
|
|
222
|
-
if self._hash is None:
|
|
223
|
-
self._hash = blake3.blake3(self.data).digest()
|
|
224
|
-
return self._hash
|
|
@@ -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
|
-
]
|
astreum/node/validation/block.py
CHANGED
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
class Block:
|
|
2
|
+
|
|
3
|
+
def __init__(self):
|
|
4
|
+
pass
|
|
5
|
+
|
|
2
6
|
@classmethod
|
|
3
|
-
def from_bytes(cls
|
|
7
|
+
def from_bytes(cls) -> 'Block':
|
|
4
8
|
"""
|
|
5
|
-
Deserialize
|
|
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
|
-
|
|
12
|
-
|
|
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
|
|
18
|
-
|
|
19
|
-
Format: [balance, code, counter, data]
|
|
15
|
+
Serialize the block into bytes.
|
|
20
16
|
"""
|
|
21
|
-
return
|
|
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.
|
|
3
|
+
Version: 0.1.20
|
|
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=
|
|
24
|
+
astreum/node/__init__.py,sha256=7yz1YHo0DCUgUQvJf75qdUo_ocl5-XZRU-Vc2NhcvJs,18639
|
|
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
|
|
@@ -32,27 +32,26 @@ astreum/node/relay/envelope.py,sha256=sDKsIvJruQKLWgWs92sx1mCjMHF7yQVoLguPygw2Pz
|
|
|
32
32
|
astreum/node/relay/message.py,sha256=uezmGjNaQK4fZmYQLCHd2YpiosaaFb8DOa3H58HS1jA,2887
|
|
33
33
|
astreum/node/relay/peer.py,sha256=DlvTR9j0BZQ1dW-p_9UGgfLvQqwNdpNLMSCYEW4FhyI,5899
|
|
34
34
|
astreum/node/relay/route.py,sha256=fyOSsAe1mfsCVeN6LtQ_OEUEb1FiC5dobZBEJKNGU9U,5814
|
|
35
|
-
astreum/node/storage/__init__.py,sha256=
|
|
36
|
-
astreum/node/storage/merkle.py,sha256=
|
|
35
|
+
astreum/node/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
|
+
astreum/node/storage/merkle.py,sha256=_rt6-jTE9jOGMpj0Ze8kegObfHJ4h-7QJdHJm_a_Di8,10243
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
55
|
-
astreum-0.1.
|
|
56
|
-
astreum-0.1.
|
|
57
|
-
astreum-0.1.
|
|
58
|
-
astreum-0.1.
|
|
53
|
+
astreum-0.1.20.dist-info/licenses/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
|
|
54
|
+
astreum-0.1.20.dist-info/METADATA,sha256=Br2J_FPsK6l8w7Af-CpsOcOn1yXDX7FV7BePSOXYJCQ,3312
|
|
55
|
+
astreum-0.1.20.dist-info/WHEEL,sha256=GHB6lJx2juba1wDgXDNlMTyM13ckjBMKf-OnwgKOCtA,91
|
|
56
|
+
astreum-0.1.20.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
|
|
57
|
+
astreum-0.1.20.dist-info/RECORD,,
|
astreum/node/validation/state.py
DELETED
|
@@ -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)
|
|
File without changes
|
|
File without changes
|