astreum 0.2.27__tar.gz → 0.2.28__tar.gz

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.

Files changed (35) hide show
  1. {astreum-0.2.27/src/astreum.egg-info → astreum-0.2.28}/PKG-INFO +1 -1
  2. {astreum-0.2.27 → astreum-0.2.28}/pyproject.toml +1 -1
  3. astreum-0.2.28/src/astreum/lispeum/environment.py +40 -0
  4. astreum-0.2.28/src/astreum/lispeum/expression.py +86 -0
  5. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/node.py +12 -183
  6. astreum-0.2.28/src/astreum/storage/__init__.py +0 -0
  7. astreum-0.2.28/src/astreum/storage/object.py +68 -0
  8. astreum-0.2.28/src/astreum/storage/setup.py +16 -0
  9. {astreum-0.2.27 → astreum-0.2.28/src/astreum.egg-info}/PKG-INFO +1 -1
  10. {astreum-0.2.27 → astreum-0.2.28}/src/astreum.egg-info/SOURCES.txt +5 -0
  11. {astreum-0.2.27 → astreum-0.2.28}/LICENSE +0 -0
  12. {astreum-0.2.27 → astreum-0.2.28}/README.md +0 -0
  13. {astreum-0.2.27 → astreum-0.2.28}/setup.cfg +0 -0
  14. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/__init__.py +0 -0
  15. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/crypto/__init__.py +0 -0
  16. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/crypto/ed25519.py +0 -0
  17. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/crypto/quadratic_form.py +0 -0
  18. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/crypto/wesolowski.py +0 -0
  19. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/crypto/x25519.py +0 -0
  20. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/format.py +0 -0
  21. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/lispeum/__init__.py +0 -0
  22. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/lispeum/parser.py +0 -0
  23. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/lispeum/tokenizer.py +0 -0
  24. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/__init__.py +0 -0
  25. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/account.py +0 -0
  26. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/accounts.py +0 -0
  27. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/block.py +0 -0
  28. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/merkle.py +0 -0
  29. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/message.py +0 -0
  30. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/patricia.py +0 -0
  31. {astreum-0.2.27 → astreum-0.2.28}/src/astreum/models/transaction.py +0 -0
  32. {astreum-0.2.27 → astreum-0.2.28}/src/astreum.egg-info/dependency_links.txt +0 -0
  33. {astreum-0.2.27 → astreum-0.2.28}/src/astreum.egg-info/requires.txt +0 -0
  34. {astreum-0.2.27 → astreum-0.2.28}/src/astreum.egg-info/top_level.txt +0 -0
  35. {astreum-0.2.27 → astreum-0.2.28}/tests/test_node_machine.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astreum
3
- Version: 0.2.27
3
+ Version: 0.2.28
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "astreum"
3
- version = "0.2.27"
3
+ version = "0.2.28"
4
4
  authors = [
5
5
  { name="Roy R. O. Okello", email="roy@stelar.xyz" },
6
6
  ]
@@ -0,0 +1,40 @@
1
+ from typing import Dict, Optional
2
+ import uuid
3
+
4
+ from astreum.lispeum.expression import Expr
5
+
6
+
7
+ class Env:
8
+ def __init__(
9
+ self,
10
+ data: Optional[Dict[str, Expr]] = None,
11
+ parent_id: Optional[uuid.UUID] = None,
12
+ max_exprs: Optional[int] = 8,
13
+ ):
14
+ self.data: Dict[str, Expr] = data if data is not None else {}
15
+ self.parent_id: Optional[uuid.UUID] = parent_id
16
+ self.max_exprs: Optional[int] = max_exprs
17
+
18
+ def put(self, name: str, value: Expr) -> None:
19
+ if (
20
+ self.max_exprs is not None
21
+ and name not in self.data
22
+ and len(self.data) >= self.max_exprs
23
+ ):
24
+ raise RuntimeError(
25
+ f"environment full: {len(self.data)} ≥ max_exprs={self.max_exprs}"
26
+ )
27
+ self.data[name] = value
28
+
29
+ def get(self, name: str) -> Optional[Expr]:
30
+ return self.data.get(name)
31
+
32
+ def pop(self, name: str) -> Optional[Expr]:
33
+ return self.data.pop(name, None)
34
+
35
+ def __repr__(self) -> str:
36
+ return (
37
+ f"Env(size={len(self.data)}, "
38
+ f"max_exprs={self.max_exprs}, "
39
+ f"parent_id={self.parent_id})"
40
+ )
@@ -0,0 +1,86 @@
1
+
2
+ from typing import List, Optional, Union
3
+
4
+
5
+ class Expr:
6
+ class ListExpr:
7
+ def __init__(self, elements: List['Expr']):
8
+ self.elements = elements
9
+
10
+ def __eq__(self, other):
11
+ if not isinstance(other, Expr.ListExpr):
12
+ return NotImplemented
13
+ return self.elements == other.elements
14
+
15
+ def __ne__(self, other):
16
+ return not self.__eq__(other)
17
+
18
+ @property
19
+ def value(self):
20
+ inner = " ".join(str(e) for e in self.elements)
21
+ return f"({inner})"
22
+
23
+
24
+ def __repr__(self):
25
+ if not self.elements:
26
+ return "()"
27
+
28
+ inner = " ".join(str(e) for e in self.elements)
29
+ return f"({inner})"
30
+
31
+ def __iter__(self):
32
+ return iter(self.elements)
33
+
34
+ def __getitem__(self, index: Union[int, slice]):
35
+ return self.elements[index]
36
+
37
+ def __len__(self):
38
+ return len(self.elements)
39
+
40
+ class Symbol:
41
+ def __init__(self, value: str):
42
+ self.value = value
43
+
44
+ def __repr__(self):
45
+ return self.value
46
+
47
+ class Integer:
48
+ def __init__(self, value: int):
49
+ self.value = value
50
+
51
+ def __repr__(self):
52
+ return str(self.value)
53
+
54
+ class String:
55
+ def __init__(self, value: str):
56
+ self.value = value
57
+
58
+ def __repr__(self):
59
+ return f'"{self.value}"'
60
+
61
+ class Boolean:
62
+ def __init__(self, value: bool):
63
+ self.value = value
64
+
65
+ def __repr__(self):
66
+ return "true" if self.value else "false"
67
+
68
+ class Function:
69
+ def __init__(self, params: List[str], body: 'Expr'):
70
+ self.params = params
71
+ self.body = body
72
+
73
+ def __repr__(self):
74
+ params_str = " ".join(self.params)
75
+ body_str = str(self.body)
76
+ return f"(fn ({params_str}) {body_str})"
77
+
78
+ class Error:
79
+ def __init__(self, message: str, origin: Optional['Expr'] = None):
80
+ self.message = message
81
+ self.origin = origin
82
+
83
+ def __repr__(self):
84
+ if self.origin is None:
85
+ return f'(error "{self.message}")'
86
+ return f'(error "{self.message}" in {self.origin})'
@@ -7,60 +7,21 @@ from typing import Tuple, Dict, Union, Optional, List
7
7
  from datetime import datetime, timedelta, timezone
8
8
  import uuid
9
9
 
10
+ from astreum.lispeum.environment import Env
11
+ from astreum.lispeum.expression import Expr
12
+ from astreum.storage.object import ObjectRequest, ObjectRequestType, ObjectResponse, ObjectResponseType
13
+ from astreum.storage.setup import storage_setup
14
+
10
15
  from .models.transaction import Transaction
11
16
  from .format import encode, decode
12
17
  from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey, X25519PublicKey
13
18
  from cryptography.hazmat.primitives import serialization
14
19
  from .crypto import ed25519, x25519
15
- from enum import IntEnum
16
20
  import blake3
17
21
  import struct
18
22
  from .models.message import Message, MessageTopic
19
23
 
20
- class ObjectRequestType(IntEnum):
21
- OBJECT_GET = 0
22
- OBJECT_PUT = 1
23
-
24
- class ObjectRequest:
25
- type: ObjectRequestType
26
- data: bytes
27
- hash: bytes
28
-
29
- def __init__(self, type: ObjectRequestType, data: bytes, hash: bytes = None):
30
- self.type = type
31
- self.data = data
32
- self.hash = hash
33
-
34
- def to_bytes(self):
35
- return encode([self.type.value, self.data, self.hash])
36
-
37
- @classmethod
38
- def from_bytes(cls, data: bytes):
39
- type_val, data_val, hash_val = decode(data)
40
- return cls(type=ObjectRequestType(type_val[0]), data=data_val, hash=hash_val)
41
-
42
- class ObjectResponseType(IntEnum):
43
- OBJECT_FOUND = 0
44
- OBJECT_PROVIDER = 1
45
- OBJECT_NEAREST_PEER = 2
46
-
47
- class ObjectResponse:
48
- type: ObjectResponseType
49
- data: bytes
50
- hash: bytes
51
-
52
- def __init__(self, type: ObjectResponseType, data: bytes, hash: bytes = None):
53
- self.type = type
54
- self.data = data
55
- self.hash = hash
56
-
57
- def to_bytes(self):
58
- return encode([self.type.value, self.data, self.hash])
59
24
 
60
- @classmethod
61
- def from_bytes(cls, data: bytes):
62
- type_val, data_val, hash_val = decode(data)
63
- return cls(type=ObjectResponseType(type_val[0]), data=data_val, hash=hash_val)
64
25
 
65
26
  class Peer:
66
27
  shared_key: bytes
@@ -109,135 +70,18 @@ def decode_ip_address(data: bytes) -> tuple[str, int]:
109
70
  raise ValueError("Invalid address byte format")
110
71
  return ip, port
111
72
 
112
- # =========
113
- # MACHINE
114
- # =========
115
-
116
- class Expr:
117
- class ListExpr:
118
- def __init__(self, elements: List['Expr']):
119
- self.elements = elements
120
-
121
- def __eq__(self, other):
122
- if not isinstance(other, Expr.ListExpr):
123
- return NotImplemented
124
- return self.elements == other.elements
125
-
126
- def __ne__(self, other):
127
- return not self.__eq__(other)
128
-
129
- @property
130
- def value(self):
131
- inner = " ".join(str(e) for e in self.elements)
132
- return f"({inner})"
133
-
134
-
135
- def __repr__(self):
136
- if not self.elements:
137
- return "()"
138
-
139
- inner = " ".join(str(e) for e in self.elements)
140
- return f"({inner})"
141
-
142
- def __iter__(self):
143
- return iter(self.elements)
144
-
145
- def __getitem__(self, index: Union[int, slice]):
146
- return self.elements[index]
147
-
148
- def __len__(self):
149
- return len(self.elements)
150
-
151
- class Symbol:
152
- def __init__(self, value: str):
153
- self.value = value
154
-
155
- def __repr__(self):
156
- return self.value
157
-
158
- class Integer:
159
- def __init__(self, value: int):
160
- self.value = value
161
-
162
- def __repr__(self):
163
- return str(self.value)
164
-
165
- class String:
166
- def __init__(self, value: str):
167
- self.value = value
168
-
169
- def __repr__(self):
170
- return f'"{self.value}"'
171
-
172
- class Boolean:
173
- def __init__(self, value: bool):
174
- self.value = value
175
-
176
- def __repr__(self):
177
- return "true" if self.value else "false"
178
-
179
- class Function:
180
- def __init__(self, params: List[str], body: 'Expr'):
181
- self.params = params
182
- self.body = body
183
-
184
- def __repr__(self):
185
- params_str = " ".join(self.params)
186
- body_str = str(self.body)
187
- return f"(fn ({params_str}) {body_str})"
188
-
189
- class Error:
190
- def __init__(self, message: str, origin: Optional['Expr'] = None):
191
- self.message = message
192
- self.origin = origin
193
-
194
- def __repr__(self):
195
- if self.origin is None:
196
- return f'(error "{self.message}")'
197
- return f'(error "{self.message}" in {self.origin})'
198
-
199
- class Env:
200
- def __init__(
201
- self,
202
- data: Optional[Dict[str, Expr]] = None,
203
- parent_id: Optional[uuid.UUID] = None,
204
- max_exprs: Optional[int] = 8,
205
- ):
206
- self.data: Dict[str, Expr] = data if data is not None else {}
207
- self.parent_id: Optional[uuid.UUID] = parent_id
208
- self.max_exprs: Optional[int] = max_exprs
209
-
210
- def put(self, name: str, value: Expr) -> None:
211
- if (
212
- self.max_exprs is not None
213
- and name not in self.data
214
- and len(self.data) >= self.max_exprs
215
- ):
216
- raise RuntimeError(
217
- f"environment full: {len(self.data)} ≥ max_exprs={self.max_exprs}"
218
- )
219
- self.data[name] = value
220
-
221
- def get(self, name: str) -> Optional[Expr]:
222
- return self.data.get(name)
223
-
224
- def pop(self, name: str) -> Optional[Expr]:
225
- return self.data.pop(name, None)
226
-
227
- def __repr__(self) -> str:
228
- return (
229
- f"Env(size={len(self.data)}, "
230
- f"max_exprs={self.max_exprs}, "
231
- f"parent_id={self.parent_id})"
232
- )
233
-
234
-
235
73
  class Node:
236
74
  def __init__(self, config: dict = {}):
237
75
  self._machine_setup()
238
76
  machine_only = bool(config.get('machine-only', True))
239
77
  if not machine_only:
240
- self._storage_setup(config=config)
78
+ (
79
+ self.storage_path,
80
+ self.memory_storage,
81
+ self.storage_get_relay_timeout,
82
+ self.storage_index
83
+ ) = storage_setup(config)
84
+
241
85
  self._relay_setup(config=config)
242
86
  self._validation_setup(config=config)
243
87
 
@@ -250,21 +94,6 @@ class Node:
250
94
  def _create_block(self):
251
95
  pass
252
96
 
253
- # STORAGE METHODS
254
- def _storage_setup(self, config: dict):
255
- storage_path_str = config.get('storage_path')
256
- if storage_path_str is None:
257
- self.storage_path = None
258
- self.memory_storage = {}
259
- else:
260
- self.storage_path = Path(storage_path_str)
261
- self.storage_path.mkdir(parents=True, exist_ok=True)
262
- self.memory_storage = None
263
-
264
- self.storage_get_relay_timeout = config.get('storage_get_relay_timeout', 5)
265
- # STORAGE INDEX: (object_hash, encoded (provider_public_key, provider_address))
266
- self.storage_index = Dict[bytes, bytes]
267
-
268
97
  def _relay_setup(self, config: dict):
269
98
  self.use_ipv6 = config.get('use_ipv6', False)
270
99
  incoming_port = config.get('incoming_port', 7373)
File without changes
@@ -0,0 +1,68 @@
1
+ from enum import IntEnum
2
+
3
+ class ObjectRequestType(IntEnum):
4
+ OBJECT_GET = 0
5
+ OBJECT_PUT = 1
6
+
7
+ class ObjectRequest:
8
+ type: ObjectRequestType
9
+ data: bytes
10
+ hash: bytes
11
+
12
+ def __init__(self, type: ObjectRequestType, data: bytes, hash: bytes = None):
13
+ self.type = type
14
+ self.data = data
15
+ self.hash = hash
16
+
17
+ def to_bytes(self):
18
+ return [self.type.value] + self.hash + self.data
19
+
20
+ @classmethod
21
+ def from_bytes(cls, data: bytes) -> "ObjectRequest":
22
+ # need at least 1 byte for type + 32 bytes for hash
23
+ if len(data) < 1 + 32:
24
+ raise ValueError(f"Too short for ObjectRequest ({len(data)} bytes)")
25
+
26
+ type_val = data[0]
27
+ try:
28
+ req_type = ObjectRequestType(type_val)
29
+ except ValueError:
30
+ raise ValueError(f"Unknown ObjectRequestType: {type_val!r}")
31
+
32
+ hash_bytes = data[1:33]
33
+ payload = data[33:]
34
+ return cls(req_type, payload, hash_bytes)
35
+
36
+ class ObjectResponseType(IntEnum):
37
+ OBJECT_FOUND = 0
38
+ OBJECT_PROVIDER = 1
39
+ OBJECT_NEAREST_PEER = 2
40
+
41
+ class ObjectResponse:
42
+ type: ObjectResponseType
43
+ data: bytes
44
+ hash: bytes
45
+
46
+ def __init__(self, type: ObjectResponseType, data: bytes, hash: bytes = None):
47
+ self.type = type
48
+ self.data = data
49
+ self.hash = hash
50
+
51
+ def to_bytes(self):
52
+ return [self.type.value] + self.hash + self.data
53
+
54
+ @classmethod
55
+ def from_bytes(cls, data: bytes) -> "ObjectResponse":
56
+ # need at least 1 byte for type + 32 bytes for hash
57
+ if len(data) < 1 + 32:
58
+ raise ValueError(f"Too short to be a valid ObjectResponse ({len(data)} bytes)")
59
+
60
+ type_val = data[0]
61
+ try:
62
+ resp_type = ObjectResponseType(type_val)
63
+ except ValueError:
64
+ raise ValueError(f"Unknown ObjectResponseType: {type_val}")
65
+
66
+ hash_bytes = data[1:33]
67
+ payload = data[33:]
68
+ return cls(resp_type, payload, hash_bytes)
@@ -0,0 +1,16 @@
1
+ from pathlib import Path
2
+ from typing import Optional, Dict, Tuple, Any
3
+
4
+ def storage_setup(config: dict
5
+ ) -> Tuple[Optional[Path], Dict[bytes, Any], int, Dict[bytes, bytes]]:
6
+ storage_path_str = config.get('storage_path')
7
+ if storage_path_str is None:
8
+ storage_path, memory_storage = None, {}
9
+ else:
10
+ storage_path = Path(storage_path_str)
11
+ storage_path.mkdir(parents=True, exist_ok=True)
12
+ memory_storage = None
13
+
14
+ timeout = config.get('storage_get_relay_timeout', 5)
15
+ storage_index: Dict[bytes, bytes] = {}
16
+ return storage_path, memory_storage, timeout, storage_index
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: astreum
3
- Version: 0.2.27
3
+ Version: 0.2.28
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
@@ -15,6 +15,8 @@ src/astreum/crypto/quadratic_form.py
15
15
  src/astreum/crypto/wesolowski.py
16
16
  src/astreum/crypto/x25519.py
17
17
  src/astreum/lispeum/__init__.py
18
+ src/astreum/lispeum/environment.py
19
+ src/astreum/lispeum/expression.py
18
20
  src/astreum/lispeum/parser.py
19
21
  src/astreum/lispeum/tokenizer.py
20
22
  src/astreum/models/__init__.py
@@ -25,4 +27,7 @@ src/astreum/models/merkle.py
25
27
  src/astreum/models/message.py
26
28
  src/astreum/models/patricia.py
27
29
  src/astreum/models/transaction.py
30
+ src/astreum/storage/__init__.py
31
+ src/astreum/storage/object.py
32
+ src/astreum/storage/setup.py
28
33
  tests/test_node_machine.py
File without changes
File without changes
File without changes
File without changes