astreum 0.3.16__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 +1 -2
  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 -62
  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 +133 -58
  21. astreum/communication/setup.py +272 -113
  22. astreum/communication/util.py +14 -0
  23. astreum/node.py +99 -92
  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 +234 -45
  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 +1 -1
  39. astreum/validation/workers/__init__.py +8 -0
  40. astreum/{consensus → validation}/workers/validation.py +360 -333
  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.16.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.16.dist-info/RECORD +0 -72
  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.16.dist-info → astreum-0.3.46.dist-info}/WHEEL +0 -0
  59. {astreum-0.3.16.dist-info → astreum-0.3.46.dist-info}/licenses/LICENSE +0 -0
  60. {astreum-0.3.16.dist-info → astreum-0.3.46.dist-info}/top_level.txt +0 -0
astreum/utils/config.py CHANGED
@@ -1,76 +1,265 @@
1
-
2
- from pathlib import Path
3
- from typing import Dict
4
-
1
+
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
7
10
  DEFAULT_PEER_TIMEOUT_SECONDS = 15 * 60 # 15 minutes
8
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
9
73
 
10
-
11
- def config_setup(config: Dict = {}):
12
- """
13
- Normalize configuration values before the node starts.
14
- """
15
- chain_str = config.get("chain", "test")
16
- if chain_str not in {"main", "test"}:
17
- chain_str = "test"
18
- config["chain"] = chain_str
19
- config["chain_id"] = 1 if chain_str == "main" else 0
20
-
21
- hot_limit_raw = config.get(
22
- "hot_storage_limit", config.get("hot_storage_default_limit", DEFAULT_HOT_STORAGE_LIMIT)
74
+ advertise_limit_raw = config.get(
75
+ "cold_storage_advertise_limit", DEFAULT_COLD_STORAGE_ADVERTISE_LIMIT
23
76
  )
24
77
  try:
25
- config["hot_storage_default_limit"] = int(hot_limit_raw)
78
+ advertise_limit = int(advertise_limit_raw)
26
79
  except (TypeError, ValueError) as exc:
27
80
  raise ValueError(
28
- f"hot_storage_limit must be an integer: {hot_limit_raw!r}"
81
+ "cold_storage_advertise_limit must be an integer: "
82
+ f"{advertise_limit_raw!r}"
29
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")
30
113
 
31
- cold_limit_raw = config.get("cold_storage_limit", DEFAULT_COLD_STORAGE_LIMIT)
114
+ incoming_queue_limit_raw = config.get(
115
+ "incoming_queue_size_limit", DEFAULT_INCOMING_QUEUE_SIZE_LIMIT_BYTES
116
+ )
32
117
  try:
33
- config["cold_storage_limit"] = int(cold_limit_raw)
118
+ incoming_queue_limit = int(incoming_queue_limit_raw)
34
119
  except (TypeError, ValueError) as exc:
35
120
  raise ValueError(
36
- f"cold_storage_limit must be an integer: {cold_limit_raw!r}"
121
+ f"incoming_queue_size_limit must be an integer: {incoming_queue_limit_raw!r}"
37
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
38
126
 
39
- cold_path_raw = config.get("cold_storage_path")
40
- if cold_path_raw:
41
- try:
42
- path_obj = Path(cold_path_raw)
43
- path_obj.mkdir(parents=True, exist_ok=True)
44
- config["cold_storage_path"] = str(path_obj)
45
- except OSError:
46
- config["cold_storage_path"] = None
47
- else:
48
- config["cold_storage_path"] = None
127
+ incoming_queue_timeout_raw = config.get(
128
+ "incoming_queue_timeout", DEFAULT_INCOMING_QUEUE_TIMEOUT_SECONDS
129
+ )
130
+ try:
131
+ incoming_queue_timeout = float(incoming_queue_timeout_raw)
132
+ except (TypeError, ValueError) as exc:
133
+ raise ValueError(
134
+ f"incoming_queue_timeout must be a number: {incoming_queue_timeout_raw!r}"
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
49
139
 
50
140
  peer_timeout_raw = config.get("peer_timeout", DEFAULT_PEER_TIMEOUT_SECONDS)
51
141
  try:
52
142
  peer_timeout = int(peer_timeout_raw)
53
143
  except (TypeError, ValueError) as exc:
54
144
  raise ValueError(
55
- f"peer_timeout must be an integer: {peer_timeout_raw!r}"
56
- ) from exc
57
-
58
- if peer_timeout <= 0:
59
- raise ValueError("peer_timeout must be a positive integer")
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
60
178
 
61
- config["peer_timeout"] = peer_timeout
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}"
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
62
191
 
63
- interval_raw = config.get("peer_timeout_interval", DEFAULT_PEER_TIMEOUT_INTERVAL_SECONDS)
192
+ outgoing_queue_limit_raw = config.get(
193
+ "outgoing_queue_size_limit", DEFAULT_OUTGOING_QUEUE_SIZE_LIMIT_BYTES
194
+ )
64
195
  try:
65
- interval = int(interval_raw)
196
+ outgoing_queue_limit = int(outgoing_queue_limit_raw)
66
197
  except (TypeError, ValueError) as exc:
67
198
  raise ValueError(
68
- f"peer_timeout_interval must be an integer: {interval_raw!r}"
199
+ f"outgoing_queue_size_limit must be an integer: {outgoing_queue_limit_raw!r}"
69
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
70
204
 
71
- if interval <= 0:
72
- raise ValueError("peer_timeout_interval must be a positive integer")
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
73
217
 
74
- config["peer_timeout_interval"] = interval
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
75
230
 
76
- 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,