astreum 0.3.9__py3-none-any.whl → 0.3.46__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.
Files changed (60) hide show
  1. astreum/__init__.py +5 -4
  2. astreum/communication/__init__.py +15 -11
  3. astreum/communication/difficulty.py +39 -0
  4. astreum/communication/disconnect.py +57 -0
  5. astreum/communication/handlers/handshake.py +105 -89
  6. astreum/communication/handlers/object_request.py +179 -149
  7. astreum/communication/handlers/object_response.py +7 -1
  8. astreum/communication/handlers/ping.py +9 -0
  9. astreum/communication/handlers/route_request.py +7 -1
  10. astreum/communication/handlers/route_response.py +7 -1
  11. astreum/communication/incoming_queue.py +96 -0
  12. astreum/communication/message_pow.py +36 -0
  13. astreum/communication/models/peer.py +4 -0
  14. astreum/communication/models/ping.py +27 -6
  15. astreum/communication/models/route.py +4 -0
  16. astreum/communication/{start.py → node.py} +10 -11
  17. astreum/communication/outgoing_queue.py +108 -0
  18. astreum/communication/processors/incoming.py +110 -37
  19. astreum/communication/processors/outgoing.py +35 -2
  20. astreum/communication/processors/peer.py +134 -0
  21. astreum/communication/setup.py +273 -112
  22. astreum/communication/util.py +14 -0
  23. astreum/node.py +99 -89
  24. astreum/storage/actions/get.py +79 -48
  25. astreum/storage/actions/set.py +171 -156
  26. astreum/storage/providers.py +24 -0
  27. astreum/storage/setup.py +23 -22
  28. astreum/utils/config.py +247 -30
  29. astreum/utils/logging.py +1 -1
  30. astreum/{consensus → validation}/__init__.py +0 -4
  31. astreum/validation/constants.py +2 -0
  32. astreum/{consensus → validation}/genesis.py +4 -6
  33. astreum/validation/models/block.py +544 -0
  34. astreum/validation/models/fork.py +511 -0
  35. astreum/{consensus → validation}/models/receipt.py +17 -4
  36. astreum/{consensus → validation}/models/transaction.py +45 -3
  37. astreum/validation/node.py +190 -0
  38. astreum/{consensus → validation}/validator.py +18 -9
  39. astreum/validation/workers/__init__.py +8 -0
  40. astreum/{consensus → validation}/workers/validation.py +361 -307
  41. astreum/verification/__init__.py +4 -0
  42. astreum/{consensus/workers/discovery.py → verification/discover.py} +1 -1
  43. astreum/verification/node.py +61 -0
  44. astreum/verification/worker.py +183 -0
  45. {astreum-0.3.9.dist-info → astreum-0.3.46.dist-info}/METADATA +43 -9
  46. astreum-0.3.46.dist-info/RECORD +79 -0
  47. astreum/consensus/models/block.py +0 -364
  48. astreum/consensus/models/chain.py +0 -66
  49. astreum/consensus/models/fork.py +0 -100
  50. astreum/consensus/setup.py +0 -83
  51. astreum/consensus/start.py +0 -67
  52. astreum/consensus/workers/__init__.py +0 -9
  53. astreum/consensus/workers/verify.py +0 -90
  54. astreum-0.3.9.dist-info/RECORD +0 -71
  55. /astreum/{consensus → validation}/models/__init__.py +0 -0
  56. /astreum/{consensus → validation}/models/account.py +0 -0
  57. /astreum/{consensus → validation}/models/accounts.py +0 -0
  58. {astreum-0.3.9.dist-info → astreum-0.3.46.dist-info}/WHEEL +0 -0
  59. {astreum-0.3.9.dist-info → astreum-0.3.46.dist-info}/licenses/LICENSE +0 -0
  60. {astreum-0.3.9.dist-info → astreum-0.3.46.dist-info}/top_level.txt +0 -0
astreum/utils/config.py CHANGED
@@ -1,48 +1,265 @@
1
1
 
2
- from pathlib import Path
3
- from typing import Dict
4
-
2
+ from pathlib import Path
3
+ from typing import Dict
4
+
5
5
  DEFAULT_HOT_STORAGE_LIMIT = 1 << 30 # 1 GiB
6
6
  DEFAULT_COLD_STORAGE_LIMIT = 10 << 30 # 10 GiB
7
+ DEFAULT_COLD_STORAGE_ADVERTISE_LIMIT = 1000
8
+ DEFAULT_INCOMING_PORT = 52780
9
+ DEFAULT_LOGGING_RETENTION_DAYS = 90
10
+ DEFAULT_PEER_TIMEOUT_SECONDS = 15 * 60 # 15 minutes
11
+ DEFAULT_PEER_TIMEOUT_INTERVAL_SECONDS = 10 # 10 seconds
12
+ DEFAULT_BOOTSTRAP_RETRY_INTERVAL_SECONDS = 30 # 30 seconds
13
+ DEFAULT_STORAGE_INDEX_INTERVAL_SECONDS = 600 # 10 minutes
14
+ DEFAULT_INCOMING_QUEUE_SIZE_LIMIT_BYTES = 64 * 1024 * 1024 # 64 MiB
15
+ DEFAULT_INCOMING_QUEUE_TIMEOUT_SECONDS = 1.0
16
+ DEFAULT_OUTGOING_QUEUE_SIZE_LIMIT_BYTES = 64 * 1024 * 1024 # 64 MiB
17
+ DEFAULT_OUTGOING_QUEUE_TIMEOUT_SECONDS = 1.0
18
+ DEFAULT_SEED = "bootstrap.astreum.org:52780"
19
+ DEFAULT_VERIFICATION_MAX_STALE_SECONDS = 10
20
+ DEFAULT_VERIFICATION_MAX_FUTURE_SKEW_SECONDS = 2
21
+
22
+
23
+ def config_setup(config: Dict = {}):
24
+ """
25
+ Normalize configuration values before the node starts.
26
+ """
27
+ chain_str = config.get("chain")
28
+ if chain_str not in {"main", "test"}:
29
+ chain_str = None
30
+ chain_id_raw = config.get("chain_id")
31
+ if chain_id_raw is None:
32
+ chain_id = 1 if chain_str == "main" else 0
33
+ else:
34
+ try:
35
+ chain_id = int(chain_id_raw)
36
+ except (TypeError, ValueError) as exc:
37
+ raise ValueError(
38
+ f"chain_id must be an integer: {chain_id_raw!r}"
39
+ ) from exc
40
+ if chain_str is None:
41
+ chain_str = "main" if chain_id == 1 else "test"
42
+ config["chain"] = chain_str
43
+ config["chain_id"] = chain_id
44
+
45
+ hot_limit_raw = config.get(
46
+ "hot_storage_limit", config.get("hot_storage_default_limit", DEFAULT_HOT_STORAGE_LIMIT)
47
+ )
48
+ try:
49
+ config["hot_storage_limit"] = int(hot_limit_raw)
50
+ except (TypeError, ValueError) as exc:
51
+ raise ValueError(
52
+ f"hot_storage_limit must be an integer: {hot_limit_raw!r}"
53
+ ) from exc
54
+
55
+ cold_limit_raw = config.get("cold_storage_limit", DEFAULT_COLD_STORAGE_LIMIT)
56
+ try:
57
+ config["cold_storage_limit"] = int(cold_limit_raw)
58
+ except (TypeError, ValueError) as exc:
59
+ raise ValueError(
60
+ f"cold_storage_limit must be an integer: {cold_limit_raw!r}"
61
+ ) from exc
62
+
63
+ cold_path_raw = config.get("cold_storage_path")
64
+ if cold_path_raw:
65
+ try:
66
+ path_obj = Path(cold_path_raw)
67
+ path_obj.mkdir(parents=True, exist_ok=True)
68
+ config["cold_storage_path"] = str(path_obj)
69
+ except OSError:
70
+ config["cold_storage_path"] = None
71
+ else:
72
+ config["cold_storage_path"] = None
7
73
 
74
+ advertise_limit_raw = config.get(
75
+ "cold_storage_advertise_limit", DEFAULT_COLD_STORAGE_ADVERTISE_LIMIT
76
+ )
77
+ try:
78
+ advertise_limit = int(advertise_limit_raw)
79
+ except (TypeError, ValueError) as exc:
80
+ raise ValueError(
81
+ "cold_storage_advertise_limit must be an integer: "
82
+ f"{advertise_limit_raw!r}"
83
+ ) from exc
84
+ if advertise_limit < -1:
85
+ raise ValueError(
86
+ "cold_storage_advertise_limit must be -1, 0, or a positive integer"
87
+ )
88
+ config["cold_storage_advertise_limit"] = advertise_limit
89
+
90
+ retention_raw = config.get(
91
+ "logging_retention_days",
92
+ config.get("logging_retention", config.get("retention_days", DEFAULT_LOGGING_RETENTION_DAYS)),
93
+ )
94
+ try:
95
+ config["logging_retention_days"] = int(retention_raw)
96
+ except (TypeError, ValueError) as exc:
97
+ raise ValueError(
98
+ f"logging_retention_days must be an integer: {retention_raw!r}"
99
+ ) from exc
100
+
101
+ if "incoming_port" in config:
102
+ incoming_port_raw = config["incoming_port"]
103
+ else:
104
+ incoming_port_raw = DEFAULT_INCOMING_PORT
105
+ try:
106
+ config["incoming_port"] = int(incoming_port_raw)
107
+ except (TypeError, ValueError) as exc:
108
+ raise ValueError(
109
+ f"incoming_port must be an integer: {incoming_port_raw!r}"
110
+ ) from exc
111
+ if config["incoming_port"] < 0:
112
+ raise ValueError("incoming_port must be 0 or a positive integer")
8
113
 
9
- def config_setup(config: Dict = {}):
10
- """
11
- Normalize configuration values before the node starts.
12
- """
13
- chain_str = config.get("chain", "test")
14
- if chain_str not in {"main", "test"}:
15
- chain_str = "test"
16
- config["chain"] = chain_str
17
- config["chain_id"] = 1 if chain_str == "main" else 0
114
+ incoming_queue_limit_raw = config.get(
115
+ "incoming_queue_size_limit", DEFAULT_INCOMING_QUEUE_SIZE_LIMIT_BYTES
116
+ )
117
+ try:
118
+ incoming_queue_limit = int(incoming_queue_limit_raw)
119
+ except (TypeError, ValueError) as exc:
120
+ raise ValueError(
121
+ f"incoming_queue_size_limit must be an integer: {incoming_queue_limit_raw!r}"
122
+ ) from exc
123
+ if incoming_queue_limit < 0:
124
+ raise ValueError("incoming_queue_size_limit must be a non-negative integer")
125
+ config["incoming_queue_size_limit"] = incoming_queue_limit
18
126
 
19
- hot_limit_raw = config.get(
20
- "hot_storage_limit", config.get("hot_storage_default_limit", DEFAULT_HOT_STORAGE_LIMIT)
127
+ incoming_queue_timeout_raw = config.get(
128
+ "incoming_queue_timeout", DEFAULT_INCOMING_QUEUE_TIMEOUT_SECONDS
21
129
  )
22
130
  try:
23
- config["hot_storage_default_limit"] = int(hot_limit_raw)
131
+ incoming_queue_timeout = float(incoming_queue_timeout_raw)
24
132
  except (TypeError, ValueError) as exc:
25
133
  raise ValueError(
26
- f"hot_storage_limit must be an integer: {hot_limit_raw!r}"
134
+ f"incoming_queue_timeout must be a number: {incoming_queue_timeout_raw!r}"
27
135
  ) from exc
136
+ if incoming_queue_timeout < 0:
137
+ raise ValueError("incoming_queue_timeout must be a non-negative number")
138
+ config["incoming_queue_timeout"] = incoming_queue_timeout
28
139
 
29
- cold_limit_raw = config.get("cold_storage_limit", DEFAULT_COLD_STORAGE_LIMIT)
140
+ peer_timeout_raw = config.get("peer_timeout", DEFAULT_PEER_TIMEOUT_SECONDS)
30
141
  try:
31
- config["cold_storage_limit"] = int(cold_limit_raw)
142
+ peer_timeout = int(peer_timeout_raw)
32
143
  except (TypeError, ValueError) as exc:
33
144
  raise ValueError(
34
- f"cold_storage_limit must be an integer: {cold_limit_raw!r}"
145
+ f"peer_timeout must be an integer: {peer_timeout_raw!r}"
146
+ ) from exc
147
+
148
+ if peer_timeout <= 0:
149
+ raise ValueError("peer_timeout must be a positive integer")
150
+
151
+ config["peer_timeout"] = peer_timeout
152
+
153
+ interval_raw = config.get("peer_timeout_interval", DEFAULT_PEER_TIMEOUT_INTERVAL_SECONDS)
154
+ try:
155
+ interval = int(interval_raw)
156
+ except (TypeError, ValueError) as exc:
157
+ raise ValueError(
158
+ f"peer_timeout_interval must be an integer: {interval_raw!r}"
159
+ ) from exc
160
+
161
+ if interval <= 0:
162
+ raise ValueError("peer_timeout_interval must be a positive integer")
163
+
164
+ config["peer_timeout_interval"] = interval
165
+
166
+ bootstrap_retry_raw = config.get(
167
+ "bootstrap_retry_interval", DEFAULT_BOOTSTRAP_RETRY_INTERVAL_SECONDS
168
+ )
169
+ try:
170
+ bootstrap_retry_interval = int(bootstrap_retry_raw)
171
+ except (TypeError, ValueError) as exc:
172
+ raise ValueError(
173
+ f"bootstrap_retry_interval must be an integer: {bootstrap_retry_raw!r}"
174
+ ) from exc
175
+ if bootstrap_retry_interval <= 0:
176
+ raise ValueError("bootstrap_retry_interval must be a positive integer")
177
+ config["bootstrap_retry_interval"] = bootstrap_retry_interval
178
+
179
+ storage_index_raw = config.get(
180
+ "storage_index_interval", DEFAULT_STORAGE_INDEX_INTERVAL_SECONDS
181
+ )
182
+ try:
183
+ storage_index_interval = int(storage_index_raw)
184
+ except (TypeError, ValueError) as exc:
185
+ raise ValueError(
186
+ f"storage_index_interval must be an integer: {storage_index_raw!r}"
35
187
  ) from exc
188
+ if storage_index_interval <= 0:
189
+ raise ValueError("storage_index_interval must be a positive integer")
190
+ config["storage_index_interval"] = storage_index_interval
36
191
 
37
- cold_path_raw = config.get("cold_storage_path")
38
- if cold_path_raw:
39
- try:
40
- path_obj = Path(cold_path_raw)
41
- path_obj.mkdir(parents=True, exist_ok=True)
42
- config["cold_storage_path"] = str(path_obj)
43
- except OSError:
44
- config["cold_storage_path"] = None
45
- else:
46
- config["cold_storage_path"] = None
192
+ outgoing_queue_limit_raw = config.get(
193
+ "outgoing_queue_size_limit", DEFAULT_OUTGOING_QUEUE_SIZE_LIMIT_BYTES
194
+ )
195
+ try:
196
+ outgoing_queue_limit = int(outgoing_queue_limit_raw)
197
+ except (TypeError, ValueError) as exc:
198
+ raise ValueError(
199
+ f"outgoing_queue_size_limit must be an integer: {outgoing_queue_limit_raw!r}"
200
+ ) from exc
201
+ if outgoing_queue_limit < 0:
202
+ raise ValueError("outgoing_queue_size_limit must be a non-negative integer")
203
+ config["outgoing_queue_size_limit"] = outgoing_queue_limit
204
+
205
+ outgoing_queue_timeout_raw = config.get(
206
+ "outgoing_queue_timeout", DEFAULT_OUTGOING_QUEUE_TIMEOUT_SECONDS
207
+ )
208
+ try:
209
+ outgoing_queue_timeout = float(outgoing_queue_timeout_raw)
210
+ except (TypeError, ValueError) as exc:
211
+ raise ValueError(
212
+ f"outgoing_queue_timeout must be a number: {outgoing_queue_timeout_raw!r}"
213
+ ) from exc
214
+ if outgoing_queue_timeout < 0:
215
+ raise ValueError("outgoing_queue_timeout must be a non-negative number")
216
+ config["outgoing_queue_timeout"] = outgoing_queue_timeout
217
+
218
+ max_stale_raw = config.get(
219
+ "verification_max_stale_seconds", DEFAULT_VERIFICATION_MAX_STALE_SECONDS
220
+ )
221
+ try:
222
+ max_stale = int(max_stale_raw)
223
+ except (TypeError, ValueError) as exc:
224
+ raise ValueError(
225
+ f"verification_max_stale_seconds must be an integer: {max_stale_raw!r}"
226
+ ) from exc
227
+ if max_stale < 0:
228
+ raise ValueError("verification_max_stale_seconds must be a non-negative integer")
229
+ config["verification_max_stale_seconds"] = max_stale
47
230
 
48
- return config
231
+ max_future_raw = config.get(
232
+ "verification_max_future_skew", DEFAULT_VERIFICATION_MAX_FUTURE_SKEW_SECONDS
233
+ )
234
+ try:
235
+ max_future = int(max_future_raw)
236
+ except (TypeError, ValueError) as exc:
237
+ raise ValueError(
238
+ f"verification_max_future_skew must be an integer: {max_future_raw!r}"
239
+ ) from exc
240
+ if max_future < 0:
241
+ raise ValueError("verification_max_future_skew must be a non-negative integer")
242
+ config["verification_max_future_skew"] = max_future
243
+
244
+ if "default_seeds" in config:
245
+ raise ValueError("default_seeds is no longer supported; use default_seed")
246
+
247
+ if "default_seed" in config:
248
+ default_seed_raw = config["default_seed"]
249
+ else:
250
+ default_seed_raw = DEFAULT_SEED
251
+
252
+ if default_seed_raw is None:
253
+ config["default_seed"] = None
254
+ elif isinstance(default_seed_raw, str):
255
+ config["default_seed"] = default_seed_raw
256
+ else:
257
+ raise ValueError("default_seed must be a string or None")
258
+
259
+ additional_seeds_raw = config.get("additional_seeds", [])
260
+ if isinstance(additional_seeds_raw, (list, tuple)):
261
+ config["additional_seeds"] = list(additional_seeds_raw)
262
+ else:
263
+ raise ValueError("additional_seeds must be a list of strings")
264
+
265
+ return config
astreum/utils/logging.py CHANGED
@@ -159,7 +159,7 @@ def logging_setup(config: dict) -> logging.LoggerAdapter:
159
159
  product = _PRODUCT_NAME
160
160
  instance_id = _derive_instance_id()
161
161
 
162
- retention_value = config.get("retention_days")
162
+ retention_value = config.get("logging_retention_days")
163
163
  retention_days = int(retention_value) if retention_value is not None else 90
164
164
 
165
165
  verbose = bool(config.get("verbose", False))
@@ -1,20 +1,16 @@
1
1
  from .models.account import Account
2
2
  from .models.accounts import Accounts
3
3
  from .models.block import Block
4
- from .models.chain import Chain
5
4
  from .models.fork import Fork
6
5
  from .models.receipt import Receipt
7
6
  from .models.transaction import Transaction
8
- from .setup import consensus_setup
9
7
 
10
8
 
11
9
  __all__ = [
12
10
  "Block",
13
- "Chain",
14
11
  "Fork",
15
12
  "Receipt",
16
13
  "Transaction",
17
14
  "Account",
18
15
  "Accounts",
19
- "consensus_setup",
20
16
  ]
@@ -0,0 +1,2 @@
1
+ TREASURY_ADDRESS = b"\x01" * 32
2
+ BURN_ADDRESS = b"\x00" * 32
@@ -2,16 +2,14 @@ from __future__ import annotations
2
2
 
3
3
  from typing import Any, List
4
4
 
5
+ from .constants import BURN_ADDRESS, TREASURY_ADDRESS
5
6
  from .models.account import Account
6
7
  from .models.accounts import Accounts
7
8
  from .models.block import Block
8
9
  from ..storage.models.atom import ZERO32
9
10
  from ..storage.models.trie import Trie
10
11
  from ..utils.integer import int_to_bytes
11
-
12
- TREASURY_ADDRESS = b"\x01" * 32
13
- BURN_ADDRESS = b"\x00" * 32
14
-
12
+ from time import time
15
13
 
16
14
  def create_genesis_block(
17
15
  node: Any,
@@ -49,13 +47,13 @@ def create_genesis_block(
49
47
  previous_block_hash=ZERO32,
50
48
  previous_block=None,
51
49
  number=0,
52
- timestamp=0,
50
+ timestamp=int(time()),
53
51
  accounts_hash=accounts_root,
54
52
  transactions_total_fees=0,
55
53
  transactions_hash=ZERO32,
56
54
  receipts_hash=ZERO32,
57
55
  delay_difficulty=0,
58
- validator_public_key=validator_pk,
56
+ validator_public_key_bytes=validator_pk,
59
57
  nonce=0,
60
58
  signature=b"",
61
59
  accounts=accounts,