astreum 0.1.15__py3-none-any.whl → 0.1.17__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/crypto/__init__.py +0 -0
- astreum/node/crypto/ed25519.py +50 -0
- astreum/node/crypto/x25519.py +31 -0
- astreum/node/relay/__init__.py +3 -0
- astreum/node/storage/merkle.py +224 -734
- astreum/node/storage/patricia.py +289 -0
- astreum/node/validation/account.py +99 -874
- astreum/node/validation/block.py +30 -0
- astreum/node/validation/transaction.py +146 -0
- {astreum-0.1.15.dist-info → astreum-0.1.17.dist-info}/METADATA +3 -2
- {astreum-0.1.15.dist-info → astreum-0.1.17.dist-info}/RECORD +18 -13
- {astreum-0.1.15.dist-info → astreum-0.1.17.dist-info}/WHEEL +1 -1
- astreum/node/storage/trie.py +0 -146
- /astreum/node/validation/{block → _block}/__init__.py +0 -0
- /astreum/node/validation/{block → _block}/create.py +0 -0
- /astreum/node/validation/{block → _block}/model.py +0 -0
- /astreum/node/validation/{block → _block}/validate.py +0 -0
- {astreum-0.1.15.dist-info → astreum-0.1.17.dist-info/licenses}/LICENSE +0 -0
- {astreum-0.1.15.dist-info → astreum-0.1.17.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class Block:
|
|
2
|
+
@classmethod
|
|
3
|
+
def from_bytes(cls, validator) -> 'Block':
|
|
4
|
+
"""
|
|
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.
|
|
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
|
+
|
|
15
|
+
def to_bytes(self) -> bytes:
|
|
16
|
+
"""
|
|
17
|
+
Serialize the Account into bytes.
|
|
18
|
+
|
|
19
|
+
Format: [balance, code, counter, data]
|
|
20
|
+
"""
|
|
21
|
+
return bytes_format.encode([
|
|
22
|
+
self.balance,
|
|
23
|
+
self.code,
|
|
24
|
+
self.counter,
|
|
25
|
+
self.data
|
|
26
|
+
])
|
|
27
|
+
|
|
28
|
+
class Chain:
|
|
29
|
+
def __init__(self, latest_block: Block):
|
|
30
|
+
self.latest_block = latest_block
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
import time
|
|
3
|
+
from .account import Account, get_account_from_storage
|
|
4
|
+
import astreum.utils.bytes_format as bytes_format
|
|
5
|
+
|
|
6
|
+
class Transaction:
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
sender: Account,
|
|
10
|
+
recipient: Account,
|
|
11
|
+
amount: int,
|
|
12
|
+
data: bytes = None,
|
|
13
|
+
counter: int = 0
|
|
14
|
+
):
|
|
15
|
+
self.sender = sender
|
|
16
|
+
self.recipient = recipient
|
|
17
|
+
self.amount = amount
|
|
18
|
+
self.data = data
|
|
19
|
+
self.counter = counter
|
|
20
|
+
self.timestamp = time.time()
|
|
21
|
+
self.signature = None
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_bytes(cls, data: bytes, resolve_accounts: bool = False, accounts=None, storage=None) -> 'Transaction':
|
|
25
|
+
"""
|
|
26
|
+
Deserialize a Transaction from its byte representation.
|
|
27
|
+
|
|
28
|
+
Expected format: [sender_hash, recipient_hash, amount, data, counter, timestamp, signature]
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
data: Serialized transaction data
|
|
32
|
+
resolve_accounts: If True, attempts to resolve account objects from storage
|
|
33
|
+
accounts: Accounts instance (required if resolve_accounts is True)
|
|
34
|
+
storage: Storage instance (required if resolve_accounts is True)
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Transaction object
|
|
38
|
+
"""
|
|
39
|
+
decoded = bytes_format.decode(data)
|
|
40
|
+
sender_public_key, recipient_public_key, amount, tx_data, counter, timestamp, signature = decoded
|
|
41
|
+
|
|
42
|
+
sender_account = None
|
|
43
|
+
recipient_account = None
|
|
44
|
+
|
|
45
|
+
if resolve_accounts:
|
|
46
|
+
if accounts is None or storage is None:
|
|
47
|
+
raise ValueError("Both accounts and storage must be provided when resolve_accounts is True")
|
|
48
|
+
sender_account = get_account_from_storage(sender_public_key, accounts, storage)
|
|
49
|
+
recipient_account = get_account_from_storage(recipient_public_key, accounts, storage)
|
|
50
|
+
else:
|
|
51
|
+
# Create minimal Account objects with just the public keys
|
|
52
|
+
sender_account = Account(sender_public_key, 0, b'', 0, b'')
|
|
53
|
+
recipient_account = Account(recipient_public_key, 0, b'', 0, b'')
|
|
54
|
+
|
|
55
|
+
transaction = cls(sender_account, recipient_account, amount, tx_data, counter)
|
|
56
|
+
transaction.timestamp = timestamp
|
|
57
|
+
transaction.signature = signature
|
|
58
|
+
return transaction
|
|
59
|
+
|
|
60
|
+
def to_bytes(self) -> bytes:
|
|
61
|
+
"""
|
|
62
|
+
Serialize the Transaction into bytes.
|
|
63
|
+
|
|
64
|
+
Format: [sender_hash, recipient_hash, amount, data, counter, timestamp, signature]
|
|
65
|
+
"""
|
|
66
|
+
return bytes_format.encode([
|
|
67
|
+
self.sender.public_key,
|
|
68
|
+
self.recipient.public_key,
|
|
69
|
+
self.amount,
|
|
70
|
+
self.data,
|
|
71
|
+
self.counter,
|
|
72
|
+
self.timestamp,
|
|
73
|
+
self.signature
|
|
74
|
+
])
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def get_tx_from_storage(hash: bytes) -> Optional[Transaction]:
|
|
78
|
+
"""Resolves storage objects to get a transaction.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
hash: Hash of the transaction and merkle root of the transaction
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Transaction object if found, None otherwise
|
|
85
|
+
"""
|
|
86
|
+
return None
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def put_tx_to_storage(transaction: Transaction):
|
|
90
|
+
"""Puts a transaction into storage.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
transaction: Transaction object to put into storage
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
None
|
|
97
|
+
"""
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def get_tx_hash(transaction: Transaction) -> bytes:
|
|
102
|
+
"""Get the hash of a transaction.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
transaction: Transaction object to get hash for
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Merkle root of the transaction body hash and signature
|
|
109
|
+
"""
|
|
110
|
+
return hash_data(get_tx_body_hash(transaction) + hash_data(transaction.signature))
|
|
111
|
+
|
|
112
|
+
def get_tx_body_hash(transaction: Transaction) -> bytes:
|
|
113
|
+
"""Get the hash of the transaction body.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
transaction: Transaction object to get hash for
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Hash of the transaction body
|
|
120
|
+
"""
|
|
121
|
+
return hash_data(transaction)
|
|
122
|
+
|
|
123
|
+
def sign_tx(transaction: Transaction, private_key: bytes) -> Transaction:
|
|
124
|
+
"""Sign a transaction.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
transaction: Transaction object to sign
|
|
128
|
+
private_key: Private key to sign with
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Signed transaction
|
|
132
|
+
"""
|
|
133
|
+
transaction.signature = hash_data(get_tx_body_hash(transaction) + private_key)
|
|
134
|
+
return transaction
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def verify_tx(transaction: Transaction) -> bool:
|
|
138
|
+
"""Verify a transaction.
|
|
139
|
+
|
|
140
|
+
Args:
|
|
141
|
+
transaction: Transaction object to verify,with sender public key
|
|
142
|
+
|
|
143
|
+
Returns:
|
|
144
|
+
True if the transaction is valid, False otherwise
|
|
145
|
+
"""
|
|
146
|
+
return True
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: astreum
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.17
|
|
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
|
|
@@ -14,6 +14,7 @@ License-File: LICENSE
|
|
|
14
14
|
Requires-Dist: pycryptodomex==3.21.0
|
|
15
15
|
Requires-Dist: cryptography==44.0.2
|
|
16
16
|
Requires-Dist: blake3==1.0.4
|
|
17
|
+
Dynamic: license-file
|
|
17
18
|
|
|
18
19
|
# lib
|
|
19
20
|
|
|
@@ -23,31 +23,36 @@ astreum/machine/environment.py,sha256=K0084U6B7wwjrDZ9b2_7cEcbBzsB7UOy_Zpbrr7B3G
|
|
|
23
23
|
astreum/machine/error.py,sha256=MvqBaZZt33rNELNhUJ2lER3TE3aS8WVqsWF2hz2AwoA,38
|
|
24
24
|
astreum/node/__init__.py,sha256=K7F21c7V9vlJuTWoSw9arsLA8RF5KNR5I6QS3Frl_Ys,19481
|
|
25
25
|
astreum/node/utils.py,sha256=amGhNYHVMjvAO-9vBRAcim-S5LlLSRudqooBN-XPdm4,702
|
|
26
|
-
astreum/node/
|
|
26
|
+
astreum/node/crypto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
+
astreum/node/crypto/ed25519.py,sha256=FRnvlN0kZlxn4j-sJKl-C9tqiz_0z4LZyXLj3KIj1TQ,1760
|
|
28
|
+
astreum/node/crypto/x25519.py,sha256=i29v4BmwKRcbz9E7NKqFDQyxzFtJUqN0St9jd7GS1uA,1137
|
|
29
|
+
astreum/node/relay/__init__.py,sha256=A6br8QSGLW7qmKYBJNIC4bEf5QMzLBFaa_FH3MaOJrs,15069
|
|
27
30
|
astreum/node/relay/bucket.py,sha256=pcmollbbM-xeHlmDxLZnzvf0Ut-9v9RoN6SijYiQuu8,2893
|
|
28
31
|
astreum/node/relay/envelope.py,sha256=sDKsIvJruQKLWgWs92sx1mCjMHF7yQVoLguPygw2Pz8,10037
|
|
29
32
|
astreum/node/relay/message.py,sha256=uezmGjNaQK4fZmYQLCHd2YpiosaaFb8DOa3H58HS1jA,2887
|
|
30
33
|
astreum/node/relay/peer.py,sha256=DlvTR9j0BZQ1dW-p_9UGgfLvQqwNdpNLMSCYEW4FhyI,5899
|
|
31
34
|
astreum/node/relay/route.py,sha256=fyOSsAe1mfsCVeN6LtQ_OEUEb1FiC5dobZBEJKNGU9U,5814
|
|
32
35
|
astreum/node/storage/__init__.py,sha256=eJL7ILUGKSKDhXZqkn3Rk5TUza39vIcwPwAW_AaIHTk,326
|
|
33
|
-
astreum/node/storage/merkle.py,sha256=
|
|
36
|
+
astreum/node/storage/merkle.py,sha256=sC7gfxPDUBgv3iiFs5PyxPgYbC4CoE-If5TQvkuoTGU,10295
|
|
37
|
+
astreum/node/storage/patricia.py,sha256=zP4whShdB7yOFcEPLE1-1PIFfx_LdK8DyMSadnF0KT0,11588
|
|
34
38
|
astreum/node/storage/storage.py,sha256=czJDhRK2rQxjOo88fhZ6j10f55RW8hWp1qq7c4yur6Y,10086
|
|
35
|
-
astreum/node/storage/trie.py,sha256=DrYNEgTS6j7WL-LtVzzCIDjSmjphjV-jL1bGXBlcyfQ,4930
|
|
36
39
|
astreum/node/storage/utils.py,sha256=CxKH9GbW31aVYs2Hwg1SirCykSnH_3_JisEayDrpOvY,5169
|
|
37
40
|
astreum/node/validation/__init__.py,sha256=D9Gmc5x5V5xgXtM32axuDMSzgKiDCz7MiUShNnuFKYc,1636
|
|
38
|
-
astreum/node/validation/account.py,sha256=
|
|
41
|
+
astreum/node/validation/account.py,sha256=mKbJSi3sfQ5K9a4zwgdyPGqT3gXHekI55yDDVpzcolo,3650
|
|
42
|
+
astreum/node/validation/block.py,sha256=ff4ZvMtIBuoY232SHxtRiwU3J-ku_hQOiqssHhIqbXY,934
|
|
39
43
|
astreum/node/validation/constants.py,sha256=ImIdLZFtMKx1iWg60YssEKl2tdDqZQnIa2JaJE6CX0o,422
|
|
40
44
|
astreum/node/validation/stake.py,sha256=Z9EPM-X9c92fpsZIYsdVpvgz4DhxQViPM-RDktWUZq8,7141
|
|
41
45
|
astreum/node/validation/state.py,sha256=QMXY7h4da-o79wMjJW93ixtepyhgcbJEf101yVuZurg,7661
|
|
46
|
+
astreum/node/validation/transaction.py,sha256=Lovx1CWIxL45glFU-LBDxI1argBLxSmDAcg1TteaOlY,4701
|
|
42
47
|
astreum/node/validation/vdf.py,sha256=HDdnqn9O_LicfE7SNCmncawKoR-ojLyjlpn74OvRNOU,2194
|
|
43
|
-
astreum/node/validation/
|
|
44
|
-
astreum/node/validation/
|
|
45
|
-
astreum/node/validation/
|
|
46
|
-
astreum/node/validation/
|
|
48
|
+
astreum/node/validation/_block/__init__.py,sha256=n2HaMG_5cpa7y5xko-c7vbHz8rL-1wAGthmr8boNrCs,216
|
|
49
|
+
astreum/node/validation/_block/create.py,sha256=apD9h92b9Y146zeppSzKNk_NJPgyBy7FhxoEkypQQNk,2515
|
|
50
|
+
astreum/node/validation/_block/model.py,sha256=d7x3_tX2MPLnGODL_5_vNjQfLdYa405blc-zL9o8HFA,2589
|
|
51
|
+
astreum/node/validation/_block/validate.py,sha256=niLexCNhEwUJLclyrdNZSvHcVa_J6jlu7J3FiWY7XBU,6232
|
|
47
52
|
astreum/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
48
53
|
astreum/utils/bytes_format.py,sha256=X4tG5GGPweNCE54bHYkLFiuLTbmpy5upO_s1Cef-MGA,2711
|
|
49
|
-
astreum-0.1.
|
|
50
|
-
astreum-0.1.
|
|
51
|
-
astreum-0.1.
|
|
52
|
-
astreum-0.1.
|
|
53
|
-
astreum-0.1.
|
|
54
|
+
astreum-0.1.17.dist-info/licenses/LICENSE,sha256=gYBvRDP-cPLmTyJhvZ346QkrYW_eleke4Z2Yyyu43eQ,1089
|
|
55
|
+
astreum-0.1.17.dist-info/METADATA,sha256=0cJVTCBktTFF2gwVAFuxDeIvojUr3pA7SeCbNCP4VuE,3312
|
|
56
|
+
astreum-0.1.17.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
57
|
+
astreum-0.1.17.dist-info/top_level.txt,sha256=1EG1GmkOk3NPmUA98FZNdKouhRyget-KiFiMk0i2Uz0,8
|
|
58
|
+
astreum-0.1.17.dist-info/RECORD,,
|
astreum/node/storage/trie.py
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
from astreum.utils.bytes_format import encode, decode
|
|
2
|
-
from astreum.utils.hash import hash_data
|
|
3
|
-
from typing import Optional, List
|
|
4
|
-
from ..storage import Storage
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class Trie:
|
|
8
|
-
def __init__(self, root: TrieNode, storage: Storage):
|
|
9
|
-
self.root = root
|
|
10
|
-
self.storage = storage
|
|
11
|
-
|
|
12
|
-
def insert(self, key: bytes, data: bytes):
|
|
13
|
-
self.root = self._insert(self.root, key, data)
|
|
14
|
-
|
|
15
|
-
def _insert(self, node: TrieNode, key: bytes, data: bytes) -> TrieNode:
|
|
16
|
-
if node is None:
|
|
17
|
-
return TrieNode(key, data)
|
|
18
|
-
if key < node.key:
|
|
19
|
-
node.children = self._insert(node.children, key, data)
|
|
20
|
-
elif key > node.key:
|
|
21
|
-
node.children = self._insert(node.children, key, data)
|
|
22
|
-
else:
|
|
23
|
-
node.data = data
|
|
24
|
-
return node
|
|
25
|
-
|
|
26
|
-
def lookup(self, key: bytes) -> bytes:
|
|
27
|
-
"""
|
|
28
|
-
Look up a key in the trie.
|
|
29
|
-
|
|
30
|
-
Args:
|
|
31
|
-
key: The key to look up
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
The data associated with the key, or None if not found
|
|
35
|
-
"""
|
|
36
|
-
return self._lookup(self.root, key)
|
|
37
|
-
|
|
38
|
-
def _lookup(self, node: Optional[TrieNode], key: bytes) -> bytes:
|
|
39
|
-
"""
|
|
40
|
-
Recursive helper for looking up a key in the trie.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
node: The current node being examined
|
|
44
|
-
key: The key to look up
|
|
45
|
-
|
|
46
|
-
Returns:
|
|
47
|
-
The data associated with the key, or None if not found
|
|
48
|
-
"""
|
|
49
|
-
if node is None:
|
|
50
|
-
return None
|
|
51
|
-
|
|
52
|
-
# If we found an exact match, return the data
|
|
53
|
-
if node.key == key:
|
|
54
|
-
return node.data
|
|
55
|
-
|
|
56
|
-
# Make sure node has a storage reference
|
|
57
|
-
if node.storage is None:
|
|
58
|
-
node.storage = self.storage
|
|
59
|
-
|
|
60
|
-
# Use child_lookup to find the most promising child
|
|
61
|
-
child_node = node.child_lookup(key)
|
|
62
|
-
if child_node is None:
|
|
63
|
-
return None
|
|
64
|
-
|
|
65
|
-
# Create and traverse to the child node
|
|
66
|
-
child_node = TrieNode.from_bytes(child_data, self.storage)
|
|
67
|
-
return self._lookup(child_node, key)
|
|
68
|
-
|
|
69
|
-
class TrieNode:
|
|
70
|
-
"""
|
|
71
|
-
A node in a trie.
|
|
72
|
-
|
|
73
|
-
Attributes:
|
|
74
|
-
key: The key of the node
|
|
75
|
-
data: The data stored in the node
|
|
76
|
-
children: The children of the node
|
|
77
|
-
storage: Reference to storage service (not serialized)
|
|
78
|
-
"""
|
|
79
|
-
def __init__(self, key: bytes, data: bytes = None, children: bytes = None, storage = None):
|
|
80
|
-
"""
|
|
81
|
-
Initialize a new TrieNode.
|
|
82
|
-
|
|
83
|
-
Args:
|
|
84
|
-
key: The key of the node
|
|
85
|
-
data: The data stored in the node
|
|
86
|
-
children: a byte string of children hashes each are 32 bytes long
|
|
87
|
-
storage: Storage instance for retrieving child nodes (not serialized)
|
|
88
|
-
"""
|
|
89
|
-
self.key = key
|
|
90
|
-
self.data = data
|
|
91
|
-
self.children = children
|
|
92
|
-
self.storage = storage
|
|
93
|
-
|
|
94
|
-
def to_bytes(self) -> bytes:
|
|
95
|
-
"""Serialize the node data (excluding storage reference)"""
|
|
96
|
-
return encode([self.key, self.data, self.children])
|
|
97
|
-
|
|
98
|
-
@classmethod
|
|
99
|
-
def from_bytes(cls, data: bytes, storage = None) -> 'TrieNode':
|
|
100
|
-
"""
|
|
101
|
-
Deserialize node data and optionally attach a storage reference.
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
data: The serialized node data
|
|
105
|
-
storage: Optional storage instance to attach to the node
|
|
106
|
-
|
|
107
|
-
Returns:
|
|
108
|
-
A new TrieNode instance
|
|
109
|
-
"""
|
|
110
|
-
key, data, children = decode(data)
|
|
111
|
-
return TrieNode(key, data, children, storage)
|
|
112
|
-
|
|
113
|
-
def hash(self) -> bytes:
|
|
114
|
-
return hash_data(self.to_bytes())
|
|
115
|
-
|
|
116
|
-
def child_lookup(self, key: bytes) -> Optional[TrieNode]:
|
|
117
|
-
"""
|
|
118
|
-
Does a binary lookup of the keys in the children of this node.
|
|
119
|
-
Uses storage to look up children and finds a starting match for the key.
|
|
120
|
-
"""
|
|
121
|
-
if self.children is None or self.storage is None:
|
|
122
|
-
return None
|
|
123
|
-
|
|
124
|
-
# Parse children bytes into a list of 32-byte hashes
|
|
125
|
-
children_hashes = []
|
|
126
|
-
for i in range(0, len(self.children), 32):
|
|
127
|
-
if i + 32 <= len(self.children):
|
|
128
|
-
children_hashes.append(self.children[i:i+32])
|
|
129
|
-
|
|
130
|
-
# Look up each child in storage and compare keys
|
|
131
|
-
for child_hash in children_hashes:
|
|
132
|
-
# Get child node data from storage
|
|
133
|
-
child_data = self.storage.get(child_hash)
|
|
134
|
-
if child_data is None:
|
|
135
|
-
continue # Skip if not found in storage
|
|
136
|
-
|
|
137
|
-
# Deserialize the child node
|
|
138
|
-
child_node = TrieNode.from_bytes(child_data, self.storage)
|
|
139
|
-
|
|
140
|
-
# Check if this child's key is a prefix of the lookup key
|
|
141
|
-
# or if the lookup key is a prefix of this child's key
|
|
142
|
-
min_len = min(len(child_node.key), len(key))
|
|
143
|
-
if child_node.key[:min_len] == key[:min_len]:
|
|
144
|
-
return child_node
|
|
145
|
-
|
|
146
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|