hive-nectar 0.2.9__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 (87) hide show
  1. hive_nectar-0.2.9.dist-info/METADATA +194 -0
  2. hive_nectar-0.2.9.dist-info/RECORD +87 -0
  3. hive_nectar-0.2.9.dist-info/WHEEL +4 -0
  4. hive_nectar-0.2.9.dist-info/entry_points.txt +2 -0
  5. hive_nectar-0.2.9.dist-info/licenses/LICENSE.txt +23 -0
  6. nectar/__init__.py +37 -0
  7. nectar/account.py +5076 -0
  8. nectar/amount.py +553 -0
  9. nectar/asciichart.py +303 -0
  10. nectar/asset.py +122 -0
  11. nectar/block.py +574 -0
  12. nectar/blockchain.py +1242 -0
  13. nectar/blockchaininstance.py +2590 -0
  14. nectar/blockchainobject.py +263 -0
  15. nectar/cli.py +5937 -0
  16. nectar/comment.py +1552 -0
  17. nectar/community.py +854 -0
  18. nectar/constants.py +95 -0
  19. nectar/discussions.py +1437 -0
  20. nectar/exceptions.py +152 -0
  21. nectar/haf.py +381 -0
  22. nectar/hive.py +630 -0
  23. nectar/imageuploader.py +114 -0
  24. nectar/instance.py +113 -0
  25. nectar/market.py +876 -0
  26. nectar/memo.py +542 -0
  27. nectar/message.py +379 -0
  28. nectar/nodelist.py +309 -0
  29. nectar/price.py +603 -0
  30. nectar/profile.py +74 -0
  31. nectar/py.typed +0 -0
  32. nectar/rc.py +333 -0
  33. nectar/snapshot.py +1024 -0
  34. nectar/storage.py +62 -0
  35. nectar/transactionbuilder.py +659 -0
  36. nectar/utils.py +630 -0
  37. nectar/version.py +3 -0
  38. nectar/vote.py +722 -0
  39. nectar/wallet.py +472 -0
  40. nectar/witness.py +728 -0
  41. nectarapi/__init__.py +12 -0
  42. nectarapi/exceptions.py +126 -0
  43. nectarapi/graphenerpc.py +596 -0
  44. nectarapi/node.py +194 -0
  45. nectarapi/noderpc.py +79 -0
  46. nectarapi/openapi.py +107 -0
  47. nectarapi/py.typed +0 -0
  48. nectarapi/rpcutils.py +98 -0
  49. nectarapi/version.py +3 -0
  50. nectarbase/__init__.py +15 -0
  51. nectarbase/ledgertransactions.py +106 -0
  52. nectarbase/memo.py +242 -0
  53. nectarbase/objects.py +521 -0
  54. nectarbase/objecttypes.py +21 -0
  55. nectarbase/operationids.py +102 -0
  56. nectarbase/operations.py +1357 -0
  57. nectarbase/py.typed +0 -0
  58. nectarbase/signedtransactions.py +89 -0
  59. nectarbase/transactions.py +11 -0
  60. nectarbase/version.py +3 -0
  61. nectargraphenebase/__init__.py +27 -0
  62. nectargraphenebase/account.py +1121 -0
  63. nectargraphenebase/aes.py +49 -0
  64. nectargraphenebase/base58.py +197 -0
  65. nectargraphenebase/bip32.py +575 -0
  66. nectargraphenebase/bip38.py +110 -0
  67. nectargraphenebase/chains.py +15 -0
  68. nectargraphenebase/dictionary.py +2 -0
  69. nectargraphenebase/ecdsasig.py +309 -0
  70. nectargraphenebase/objects.py +130 -0
  71. nectargraphenebase/objecttypes.py +8 -0
  72. nectargraphenebase/operationids.py +5 -0
  73. nectargraphenebase/operations.py +25 -0
  74. nectargraphenebase/prefix.py +13 -0
  75. nectargraphenebase/py.typed +0 -0
  76. nectargraphenebase/signedtransactions.py +221 -0
  77. nectargraphenebase/types.py +557 -0
  78. nectargraphenebase/unsignedtransactions.py +288 -0
  79. nectargraphenebase/version.py +3 -0
  80. nectarstorage/__init__.py +57 -0
  81. nectarstorage/base.py +317 -0
  82. nectarstorage/exceptions.py +15 -0
  83. nectarstorage/interfaces.py +244 -0
  84. nectarstorage/masterpassword.py +237 -0
  85. nectarstorage/py.typed +0 -0
  86. nectarstorage/ram.py +27 -0
  87. nectarstorage/sqlite.py +343 -0
nectar/block.py ADDED
@@ -0,0 +1,574 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ from datetime import date, datetime
5
+ from typing import Any
6
+
7
+ from nectar.instance import shared_blockchain_instance
8
+ from nectar.utils import formatTimeString, parse_time
9
+
10
+ from .blockchainobject import BlockchainObject
11
+ from .exceptions import BlockDoesNotExistsException
12
+
13
+
14
+ class Block(BlockchainObject):
15
+ """Read a single block from the chain
16
+
17
+ :param int block: block number
18
+ :param Hive blockchain_instance: Hive
19
+ instance
20
+ :param bool lazy: Use lazy loading
21
+ :param bool only_ops: Includes only operations, when set to True (default: False)
22
+ :param bool only_virtual_ops: Includes only virtual operations (default: False)
23
+
24
+ Instances of this class are dictionaries that come with additional
25
+ methods (see below) that allow dealing with a block and its
26
+ corresponding functions.
27
+
28
+ When only_virtual_ops is set to True, only_ops is always set to True.
29
+
30
+ In addition to the block data, the block number is stored as self["id"] or self.identifier.
31
+
32
+ .. code-block:: python
33
+
34
+ >>> from nectar.block import Block
35
+ >>> block = Block(1)
36
+ >>> print(block)
37
+ <Block 1>
38
+
39
+ .. note:: This class comes with its own caching function to reduce the
40
+ load on the API server. Instances of this class can be
41
+ refreshed with ``Account.refresh()``.
42
+
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ block: int | float | dict,
48
+ only_ops: bool = False,
49
+ only_virtual_ops: bool = False,
50
+ full: bool = True,
51
+ lazy: bool = False,
52
+ blockchain_instance: Any = None,
53
+ **kwargs,
54
+ ) -> None:
55
+ """
56
+ Initialize a Block object representing a single blockchain block.
57
+
58
+ block may be an integer (block number), a float (will be converted to int), or a dict containing block data (which will be parsed). Controls:
59
+ - only_ops: load only operations from the block.
60
+ - only_virtual_ops: load only virtual operations.
61
+ - full: if True, populate full block data; if False, keep a minimal representation.
62
+ - lazy: if True, defer fetching full data until needed.
63
+
64
+ If no identifier is present after initialization, the block's identifier is set to its numeric block number.
65
+ """
66
+ self.full = full
67
+ self.lazy = lazy
68
+ self.only_ops = only_ops
69
+ self.only_virtual_ops = only_virtual_ops
70
+ if isinstance(block, float):
71
+ block = int(block)
72
+ elif isinstance(block, dict):
73
+ block = self._parse_json_data(block)
74
+ super().__init__(
75
+ block,
76
+ lazy=lazy,
77
+ full=full,
78
+ blockchain_instance=blockchain_instance,
79
+ **kwargs,
80
+ )
81
+ if self.identifier is None:
82
+ self.identifier = self.get(self.id_item)
83
+
84
+ def _parse_json_data(self, block: dict) -> dict:
85
+ parse_times = [
86
+ "timestamp",
87
+ ]
88
+ for p in parse_times:
89
+ if p in block and isinstance(block.get(p), str):
90
+ block[p] = parse_time(block.get(p, "1970-01-01T00:00:00"))
91
+ if "transactions" in block:
92
+ for i in range(len(block["transactions"])):
93
+ if "expiration" in block["transactions"][i] and isinstance(
94
+ block["transactions"][i]["expiration"], str
95
+ ):
96
+ block["transactions"][i]["expiration"] = parse_time(
97
+ block["transactions"][i]["expiration"]
98
+ )
99
+ elif "operations" in block:
100
+ for i in range(len(block["operations"])):
101
+ if "timestamp" in block["operations"][i] and isinstance(
102
+ block["operations"][i]["timestamp"], str
103
+ ):
104
+ block["operations"][i]["timestamp"] = parse_time(
105
+ block["operations"][i]["timestamp"]
106
+ )
107
+ return block
108
+
109
+ def json(self) -> dict:
110
+ output = self.copy()
111
+ parse_times = [
112
+ "timestamp",
113
+ ]
114
+ for p in parse_times:
115
+ if p in output:
116
+ p_date = output.get(p, datetime(1970, 1, 1, 0, 0))
117
+ if isinstance(p_date, (datetime, date)):
118
+ output[p] = formatTimeString(p_date)
119
+ else:
120
+ output[p] = p_date
121
+
122
+ if "transactions" in output:
123
+ for i in range(len(output["transactions"])):
124
+ if "expiration" in output["transactions"][i] and isinstance(
125
+ output["transactions"][i]["expiration"], (datetime, date)
126
+ ):
127
+ output["transactions"][i]["expiration"] = formatTimeString(
128
+ output["transactions"][i]["expiration"]
129
+ )
130
+ elif "operations" in output:
131
+ for i in range(len(output["operations"])):
132
+ if "timestamp" in output["operations"][i] and isinstance(
133
+ output["operations"][i]["timestamp"], (datetime, date)
134
+ ):
135
+ output["operations"][i]["timestamp"] = formatTimeString(
136
+ output["operations"][i]["timestamp"]
137
+ )
138
+
139
+ ret = json.loads(str(json.dumps(output)))
140
+ output = self._parse_json_data(output)
141
+ return ret
142
+
143
+ def refresh(self) -> None:
144
+ """Even though blocks never change, you freshly obtain its contents
145
+ from an API with this method
146
+ """
147
+ if self.identifier is None:
148
+ return
149
+ if not self.blockchain.is_connected():
150
+ return
151
+ self.blockchain.rpc.set_next_node_on_empty_reply(False)
152
+ if self.only_ops or self.only_virtual_ops:
153
+ ops_ops = self.blockchain.rpc.get_ops_in_block(
154
+ {"block_num": self.identifier, "only_virtual": self.only_virtual_ops}
155
+ )
156
+ ops = ops_ops["ops"] if ops_ops is not None else []
157
+ timestamp = ops[0]["timestamp"] if ops else "1970-01-01T00:00:00"
158
+ block = {
159
+ "block": self.identifier,
160
+ "timestamp": timestamp,
161
+ "operations": ops,
162
+ }
163
+ else:
164
+ block = self.blockchain.rpc.get_block({"block_num": self.identifier})
165
+ if block and "block" in block:
166
+ block = block["block"]
167
+ if not block:
168
+ message = f"Block {self.identifier} does not exist or is not available from {self.blockchain.rpc.url}"
169
+ raise BlockDoesNotExistsException(message)
170
+ block = self._parse_json_data(block)
171
+ super().__init__(block, lazy=self.lazy, full=self.full, blockchain_instance=self.blockchain)
172
+
173
+ @property
174
+ def block_num(self) -> int | None:
175
+ """Returns the block number"""
176
+ if "block_id" in self:
177
+ return int(self["block_id"][:8], base=16)
178
+ elif "block" in self:
179
+ return int(self["block"])
180
+ else:
181
+ return None
182
+
183
+ def time(self) -> datetime:
184
+ """Return a datetime instance for the timestamp of this block"""
185
+ return self["timestamp"]
186
+
187
+ @property
188
+ def transactions(self) -> list[dict[str, Any]]:
189
+ """Returns all transactions as list"""
190
+ if self.only_ops or self.only_virtual_ops:
191
+ return list()
192
+ trxs = []
193
+ if "transactions" not in self:
194
+ return []
195
+ trx_id = 0
196
+ for trx in self["transactions"]:
197
+ trx_new = {"transaction_id": self["transaction_ids"][trx_id]}
198
+ trx_new.update(trx.copy())
199
+ trx_new.update({"block_num": self.block_num, "transaction_num": trx_id})
200
+ trxs.append(trx_new)
201
+ trx_id += 1
202
+ return trxs
203
+
204
+ @property
205
+ def operations(self) -> list[Any]:
206
+ """Returns all block operations as list"""
207
+
208
+ def _normalize_op_type(op_type: Any) -> Any:
209
+ if isinstance(op_type, int):
210
+ try:
211
+ from nectarbase.operationids import getOperationNameForId
212
+
213
+ return getOperationNameForId(op_type)
214
+ except Exception:
215
+ return op_type
216
+ return op_type
217
+
218
+ if (self.only_ops or self.only_virtual_ops) and "operations" in self:
219
+ ops = self["operations"]
220
+ # Normalize get_ops_in_block format (which wraps op in "op" key)
221
+ normalized_ops = []
222
+ for x in ops:
223
+ if isinstance(x, dict) and "op" in x:
224
+ # Wrapper found: get_ops_in_block format
225
+ raw_op = x["op"]
226
+ if isinstance(raw_op, list):
227
+ op_dict = {
228
+ "type": _normalize_op_type(raw_op[0]),
229
+ "value": raw_op[1],
230
+ }
231
+ elif isinstance(raw_op, dict):
232
+ op_dict = raw_op.copy()
233
+ if "type" in op_dict:
234
+ op_dict["type"] = _normalize_op_type(op_dict["type"])
235
+ else:
236
+ continue # Should not happen
237
+
238
+ # Inject metadata from wrapper
239
+ if "trx_id" in x:
240
+ op_dict["transaction_id"] = x["trx_id"]
241
+ if "timestamp" in x:
242
+ op_dict["timestamp"] = x["timestamp"]
243
+ if "block" in x:
244
+ op_dict["block_num"] = x["block"]
245
+
246
+ normalized_ops.append(op_dict)
247
+ elif isinstance(x, (list, tuple)) and len(x) >= 2:
248
+ normalized_ops.append({"type": _normalize_op_type(x[0]), "value": x[1]})
249
+ elif isinstance(x, dict) and "type" in x and "value" in x:
250
+ op_dict = x.copy()
251
+ op_dict["type"] = _normalize_op_type(op_dict["type"])
252
+ normalized_ops.append(op_dict)
253
+ else:
254
+ # Legacy or direct format?
255
+ normalized_ops.append(x)
256
+ return normalized_ops
257
+ ops = []
258
+ trxs = []
259
+ if "transactions" in self:
260
+ trxs = self["transactions"]
261
+
262
+ for tx_idx, tx in enumerate(trxs):
263
+ if "operations" not in tx:
264
+ continue
265
+
266
+ # Get transaction_id if available (it is usually in a separate list in the block)
267
+ current_trx_id = None
268
+ if "transaction_ids" in self and len(self["transaction_ids"]) > tx_idx:
269
+ current_trx_id = self["transaction_ids"][tx_idx]
270
+ # Provide fallback if it was somehow already in tx (e.g. from different API)
271
+ elif "transaction_id" in tx:
272
+ current_trx_id = tx["transaction_id"]
273
+
274
+ for op in tx["operations"]:
275
+ # Replace op id by op name when numeric
276
+ if isinstance(op, (list, tuple)) and len(op) > 0:
277
+ op[0] = _normalize_op_type(op[0])
278
+ if isinstance(op, list):
279
+ if self.only_ops or self.only_virtual_ops:
280
+ op_dict = {"type": op[0], "value": op[1]}
281
+ # Inject formatting that helpers.py expects
282
+ if current_trx_id:
283
+ op_dict["transaction_id"] = current_trx_id
284
+
285
+ if "block_num" in tx:
286
+ op_dict["block_num"] = tx["block_num"]
287
+ elif self.block_num:
288
+ op_dict["block_num"] = self.block_num
289
+
290
+ op_dict["timestamp"] = self.time()
291
+ ops.append(op_dict)
292
+ else:
293
+ ops.append(list(op))
294
+ elif isinstance(op, dict):
295
+ # If op is already a dictionary, we still need to inject metadata if we are in only_ops mode
296
+ if self.only_ops or self.only_virtual_ops:
297
+ op_dict = op.copy()
298
+ if "type" in op_dict:
299
+ op_dict["type"] = _normalize_op_type(op_dict["type"])
300
+
301
+ # In some cases op might be {"op": {"type": ..., "value": ...}} ??
302
+ # But loop above handles raw operations list.
303
+ # Assuming op is {"type": ..., "value": ...} or similar structure
304
+
305
+ if current_trx_id and "transaction_id" not in op_dict:
306
+ op_dict["transaction_id"] = current_trx_id
307
+
308
+ if "block_num" not in op_dict:
309
+ if "block_num" in tx:
310
+ op_dict["block_num"] = tx["block_num"]
311
+ elif self.block_num:
312
+ op_dict["block_num"] = self.block_num
313
+
314
+ if "timestamp" not in op_dict:
315
+ op_dict["timestamp"] = self.time()
316
+ ops.append(op_dict)
317
+ else:
318
+ ops.append(op.copy())
319
+ else:
320
+ ops.append(op.copy())
321
+ return ops
322
+
323
+ @property
324
+ def json_transactions(self) -> list[dict[str, Any]]:
325
+ """Returns all transactions as list, all dates are strings."""
326
+ if self.only_ops or self.only_virtual_ops:
327
+ return list()
328
+ trxs = []
329
+ if "transactions" not in self:
330
+ return []
331
+ trx_id = 0
332
+ for trx in self["transactions"]:
333
+ trx_new = {"transaction_id": self["transaction_ids"][trx_id]}
334
+ trx_new.update(trx.copy())
335
+ trx_new.update({"block_num": self.block_num, "transaction_num": trx_id})
336
+ if "expiration" in trx:
337
+ p_date = trx.get("expiration", datetime(1970, 1, 1, 0, 0))
338
+ if isinstance(p_date, (datetime, date)):
339
+ trx_new.update({"expiration": formatTimeString(p_date)})
340
+
341
+ trxs.append(trx_new)
342
+ trx_id += 1
343
+ return trxs
344
+
345
+ @property
346
+ def json_operations(self) -> list[Any]:
347
+ """Returns all block operations as list, all dates are strings."""
348
+ if self.only_ops or self.only_virtual_ops:
349
+ return self["operations"]
350
+ ops = []
351
+ for tx in self["transactions"]:
352
+ for op in tx["operations"]:
353
+ if "operations" not in tx:
354
+ continue
355
+ # Replace op id by op name when numeric
356
+ if isinstance(op, (list, tuple)) and len(op) > 0 and isinstance(op[0], int):
357
+ try:
358
+ from nectarbase.operationids import getOperationNameForId
359
+
360
+ op[0] = getOperationNameForId(op[0])
361
+ except Exception:
362
+ pass
363
+ if isinstance(op, list):
364
+ op_new = list(op)
365
+ else:
366
+ op_new = op.copy()
367
+ if "timestamp" in op:
368
+ p_date = op.get("timestamp", datetime(1970, 1, 1, 0, 0))
369
+ if isinstance(p_date, (datetime, date)):
370
+ if isinstance(op_new, dict):
371
+ op_new.update({"timestamp": formatTimeString(p_date)})
372
+ else:
373
+ # Handle list case - find timestamp in list and update it
374
+ for i, item in enumerate(op_new):
375
+ if isinstance(item, dict) and "timestamp" in item:
376
+ op_new[i] = {
377
+ **item,
378
+ "timestamp": formatTimeString(p_date),
379
+ }
380
+ break
381
+ ops.append(op_new)
382
+ return ops
383
+
384
+ def ops_statistics(self, add_to_ops_stat: dict[str, int] | None = None) -> dict[str, int]:
385
+ """Returns a statistic with the occurrence of the different operation types"""
386
+ if add_to_ops_stat is None:
387
+ import nectarbase.operationids
388
+
389
+ ops_stat = nectarbase.operationids.operations.copy()
390
+ for key in ops_stat:
391
+ if isinstance(key, int):
392
+ ops_stat[key] = 0
393
+ else:
394
+ ops_stat = add_to_ops_stat.copy()
395
+ for op in self.operations:
396
+ if "op" in op:
397
+ op = op["op"]
398
+ if isinstance(op, dict) and "type" in op:
399
+ op_type = op["type"]
400
+ if len(op_type) > 10 and op_type[len(op_type) - 10 :] == "_operation":
401
+ op_type = op_type[:-10]
402
+ else:
403
+ op_type = op[0]
404
+ if op_type in ops_stat:
405
+ ops_stat[op_type] += 1
406
+ return ops_stat
407
+
408
+
409
+ class BlockHeader(BlockchainObject):
410
+ """Read a single block header from the chain
411
+
412
+ :param int block: block number
413
+ :param Hive blockchain_instance: Hive
414
+ instance
415
+ :param bool lazy: Use lazy loading
416
+
417
+ In addition to the block data, the block number is stored as self["id"] or self.identifier.
418
+
419
+ .. code-block:: python
420
+
421
+ >>> from nectar.block import BlockHeader
422
+ >>> block = BlockHeader(1)
423
+ >>> print(block)
424
+ <BlockHeader 1>
425
+
426
+ """
427
+
428
+ def __init__(
429
+ self,
430
+ block: int | float | dict,
431
+ full: bool = True,
432
+ lazy: bool = False,
433
+ blockchain_instance: Any = None,
434
+ **kwargs,
435
+ ) -> None:
436
+ """
437
+ Initialize a BlockHeader.
438
+
439
+ One-line summary:
440
+ Create a BlockHeader wrapper for a block header, optionally in lazy or full mode.
441
+
442
+ Parameters:
443
+ block (int | float | dict): Block number (floats are converted to int) or a header dict.
444
+ full (bool): If True, populate the object with full header data; otherwise keep a minimal representation.
445
+ lazy (bool): If True, delay API fetching until data is accessed.
446
+
447
+ Notes:
448
+ If no blockchain_instance is provided, the module's shared blockchain instance is used.
449
+ """
450
+ self.full = full
451
+ self.lazy = lazy
452
+ if isinstance(block, float):
453
+ block = int(block)
454
+ super().__init__(
455
+ block,
456
+ lazy=lazy,
457
+ full=full,
458
+ blockchain_instance=blockchain_instance,
459
+ **kwargs,
460
+ )
461
+
462
+ def refresh(self) -> None:
463
+ """Even though blocks never change, you freshly obtain its contents
464
+ from an API with this method
465
+ """
466
+ if not self.blockchain.is_connected():
467
+ return None
468
+ self.blockchain.rpc.set_next_node_on_empty_reply(False)
469
+ block = self.blockchain.rpc.get_block_header({"block_num": self.identifier})
470
+ if block is not None and "header" in block:
471
+ block = block["header"]
472
+ if not block:
473
+ raise BlockDoesNotExistsException(str(self.identifier))
474
+ block = self._parse_json_data(block)
475
+ super().__init__(block, lazy=self.lazy, full=self.full, blockchain_instance=self.blockchain)
476
+
477
+ def time(self) -> datetime:
478
+ """Return a datetime instance for the timestamp of this block"""
479
+ return self["timestamp"]
480
+
481
+ @property
482
+ def block_num(self) -> int:
483
+ """Returns the block number"""
484
+ if self.identifier is None:
485
+ raise ValueError("Block identifier is not set")
486
+ if isinstance(self.identifier, int):
487
+ return self.identifier
488
+ # Try to convert string or other types to int
489
+ return int(self.identifier)
490
+
491
+ def _parse_json_data(self, block: dict) -> dict:
492
+ parse_times = [
493
+ "timestamp",
494
+ ]
495
+ for p in parse_times:
496
+ if p in block and isinstance(block.get(p), str):
497
+ block[p] = parse_time(block.get(p, "1970-01-01T00:00:00"))
498
+ return block
499
+
500
+ def json(self) -> dict:
501
+ output = self.copy()
502
+ parse_times = [
503
+ "timestamp",
504
+ ]
505
+ for p in parse_times:
506
+ if p in output:
507
+ p_date = output.get(p, datetime(1970, 1, 1, 0, 0))
508
+ if isinstance(p_date, (datetime, date)):
509
+ output[p] = formatTimeString(p_date)
510
+ else:
511
+ output[p] = p_date
512
+ return json.loads(str(json.dumps(output)))
513
+
514
+
515
+ class Blocks(list):
516
+ """Obtain a list of blocks
517
+
518
+ :param list name_list: list of accounts to fetch
519
+ :param int count: (optional) maximum number of accounts
520
+ to fetch per call, defaults to 100
521
+ :param Hive blockchain_instance: Hive() instance to use when
522
+ accessing RPC
523
+ """
524
+
525
+ def __init__(
526
+ self,
527
+ starting_block_num: int,
528
+ count: int = 1000,
529
+ lazy: bool = False,
530
+ full: bool = True,
531
+ only_ops: bool = False,
532
+ only_virtual_ops: bool = False,
533
+ blockchain_instance: Any = None,
534
+ **kwargs,
535
+ ) -> None:
536
+ """
537
+ Initialize a Blocks collection by fetching a contiguous range of blocks from the chain and populating the list with Block objects.
538
+
539
+ If a blockchain_instance is provided it is used; otherwise the shared blockchain instance is used. If the chosen instance is not connected, the initializer returns early and the Blocks object remains empty.
540
+
541
+ Parameters:
542
+ starting_block_num (int): First block number to retrieve.
543
+ count (int, optional): Number of consecutive blocks to fetch. Defaults to 1000.
544
+ lazy (bool, optional): If True, create Block objects in lazy mode (defer full parsing). Defaults to False.
545
+ full (bool, optional): If True, create Block objects with full data loaded (subject to lazy). Defaults to True.
546
+ only_ops (bool, optional): If True, blocks will contain only regular operations (no block metadata). Defaults to False.
547
+ only_virtual_ops (bool, optional): If True, blocks will contain only virtual operations. Defaults to False.
548
+ """
549
+ self.blockchain = blockchain_instance or shared_blockchain_instance()
550
+
551
+ if not self.blockchain.is_connected():
552
+ return
553
+ blocks = []
554
+
555
+ self.blockchain.rpc.set_next_node_on_empty_reply(False)
556
+
557
+ blocks = self.blockchain.rpc.get_block_range(
558
+ {"starting_block_num": starting_block_num, "count": count}
559
+ )["blocks"]
560
+
561
+ super().__init__(
562
+ [
563
+ Block(
564
+ x,
565
+ lazy=lazy,
566
+ full=full,
567
+ only_ops=only_ops,
568
+ only_virtual_ops=only_virtual_ops,
569
+ blockchain_instance=self.blockchain,
570
+ **kwargs,
571
+ )
572
+ for x in blocks
573
+ ]
574
+ )