hive-nectar 0.0.2__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 hive-nectar might be problematic. Click here for more details.

Files changed (86) hide show
  1. hive_nectar-0.0.2.dist-info/METADATA +182 -0
  2. hive_nectar-0.0.2.dist-info/RECORD +86 -0
  3. hive_nectar-0.0.2.dist-info/WHEEL +4 -0
  4. hive_nectar-0.0.2.dist-info/entry_points.txt +2 -0
  5. hive_nectar-0.0.2.dist-info/licenses/LICENSE.txt +23 -0
  6. nectar/__init__.py +32 -0
  7. nectar/account.py +4371 -0
  8. nectar/amount.py +475 -0
  9. nectar/asciichart.py +270 -0
  10. nectar/asset.py +82 -0
  11. nectar/block.py +446 -0
  12. nectar/blockchain.py +1178 -0
  13. nectar/blockchaininstance.py +2284 -0
  14. nectar/blockchainobject.py +221 -0
  15. nectar/blurt.py +563 -0
  16. nectar/cli.py +6285 -0
  17. nectar/comment.py +1217 -0
  18. nectar/community.py +513 -0
  19. nectar/constants.py +111 -0
  20. nectar/conveyor.py +309 -0
  21. nectar/discussions.py +1709 -0
  22. nectar/exceptions.py +149 -0
  23. nectar/hive.py +546 -0
  24. nectar/hivesigner.py +420 -0
  25. nectar/imageuploader.py +72 -0
  26. nectar/instance.py +129 -0
  27. nectar/market.py +1013 -0
  28. nectar/memo.py +449 -0
  29. nectar/message.py +357 -0
  30. nectar/nodelist.py +444 -0
  31. nectar/price.py +557 -0
  32. nectar/profile.py +65 -0
  33. nectar/rc.py +308 -0
  34. nectar/snapshot.py +726 -0
  35. nectar/steem.py +582 -0
  36. nectar/storage.py +53 -0
  37. nectar/transactionbuilder.py +622 -0
  38. nectar/utils.py +545 -0
  39. nectar/version.py +2 -0
  40. nectar/vote.py +557 -0
  41. nectar/wallet.py +472 -0
  42. nectar/witness.py +617 -0
  43. nectarapi/__init__.py +11 -0
  44. nectarapi/exceptions.py +123 -0
  45. nectarapi/graphenerpc.py +589 -0
  46. nectarapi/node.py +178 -0
  47. nectarapi/noderpc.py +229 -0
  48. nectarapi/rpcutils.py +97 -0
  49. nectarapi/version.py +2 -0
  50. nectarbase/__init__.py +14 -0
  51. nectarbase/ledgertransactions.py +75 -0
  52. nectarbase/memo.py +243 -0
  53. nectarbase/objects.py +429 -0
  54. nectarbase/objecttypes.py +22 -0
  55. nectarbase/operationids.py +102 -0
  56. nectarbase/operations.py +1297 -0
  57. nectarbase/signedtransactions.py +48 -0
  58. nectarbase/transactions.py +11 -0
  59. nectarbase/version.py +2 -0
  60. nectargrapheneapi/__init__.py +6 -0
  61. nectargraphenebase/__init__.py +27 -0
  62. nectargraphenebase/account.py +846 -0
  63. nectargraphenebase/aes.py +52 -0
  64. nectargraphenebase/base58.py +192 -0
  65. nectargraphenebase/bip32.py +494 -0
  66. nectargraphenebase/bip38.py +134 -0
  67. nectargraphenebase/chains.py +149 -0
  68. nectargraphenebase/dictionary.py +3 -0
  69. nectargraphenebase/ecdsasig.py +326 -0
  70. nectargraphenebase/objects.py +123 -0
  71. nectargraphenebase/objecttypes.py +6 -0
  72. nectargraphenebase/operationids.py +3 -0
  73. nectargraphenebase/operations.py +23 -0
  74. nectargraphenebase/prefix.py +11 -0
  75. nectargraphenebase/py23.py +38 -0
  76. nectargraphenebase/signedtransactions.py +201 -0
  77. nectargraphenebase/types.py +419 -0
  78. nectargraphenebase/unsignedtransactions.py +283 -0
  79. nectargraphenebase/version.py +2 -0
  80. nectarstorage/__init__.py +38 -0
  81. nectarstorage/base.py +306 -0
  82. nectarstorage/exceptions.py +16 -0
  83. nectarstorage/interfaces.py +237 -0
  84. nectarstorage/masterpassword.py +239 -0
  85. nectarstorage/ram.py +30 -0
  86. nectarstorage/sqlite.py +334 -0
nectar/nodelist.py ADDED
@@ -0,0 +1,444 @@
1
+ # -*- coding: utf-8 -*-
2
+ import json
3
+ import logging
4
+ from timeit import default_timer as timer
5
+
6
+ from nectar.account import Account
7
+ from nectar.instance import shared_blockchain_instance
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ def node_answer_time(node):
13
+ try:
14
+ from nectar.blockchaininstance import BlockChainInstance
15
+
16
+ stm_local = BlockChainInstance(node=node, num_retries=2, num_retries_call=2, timeout=10)
17
+ start = timer()
18
+ stm_local.get_network(use_stored_data=False)
19
+ stop = timer()
20
+ rpc_answer_time = stop - start
21
+ except KeyboardInterrupt:
22
+ rpc_answer_time = float("inf")
23
+ raise KeyboardInterrupt()
24
+ except Exception:
25
+ rpc_answer_time = float("inf")
26
+ return rpc_answer_time
27
+
28
+
29
+ class NodeList(list):
30
+ """Returns HIVE/STEEM nodes as list
31
+
32
+ .. code-block:: python
33
+
34
+ from nectar.nodelist import NodeList
35
+ n = NodeList()
36
+ nodes_urls = n.get_nodes()
37
+
38
+ """
39
+
40
+ def __init__(self):
41
+ nodes = [
42
+ {
43
+ "url": "https://api.steemit.com",
44
+ "version": "0.20.2",
45
+ "type": "appbase",
46
+ "owner": "steemit",
47
+ "hive": False,
48
+ "score": 50,
49
+ },
50
+ {
51
+ "url": "https://api.hive.blog",
52
+ "version": "1.27.8",
53
+ "type": "appbase",
54
+ "owner": "hive",
55
+ "hive": True,
56
+ "score": 80,
57
+ },
58
+ {
59
+ "url": "https://api.syncad.com",
60
+ "version": "1.27.8",
61
+ "type": "appbase",
62
+ "owner": "syncad",
63
+ "hive": True,
64
+ "score": 70,
65
+ },
66
+ {
67
+ "url": "https://anyx.io",
68
+ "version": "1.27.4",
69
+ "type": "appbase",
70
+ "owner": "anyx",
71
+ "hive": True,
72
+ "score": 60,
73
+ },
74
+ {
75
+ "url": "https://api.openhive.network",
76
+ "version": "1.27.8",
77
+ "type": "appbase",
78
+ "owner": "gtg",
79
+ "hive": True,
80
+ "score": 50,
81
+ },
82
+ {
83
+ "url": "https://rpc.mahdiyari.info",
84
+ "version": "1.27.5",
85
+ "type": "appbase",
86
+ "owner": "mahdiyari",
87
+ "hive": True,
88
+ "score": 50,
89
+ },
90
+ {
91
+ "url": "https://api.c0ff33a.uk",
92
+ "version": "1.27.5",
93
+ "type": "appbase",
94
+ "owner": "c0ff33a",
95
+ "hive": True,
96
+ "score": 40,
97
+ },
98
+ {
99
+ "url": "https://api.deathwing.me",
100
+ "version": "1.27.5",
101
+ "type": "appbase",
102
+ "owner": "deathwing",
103
+ "hive": True,
104
+ "score": 40,
105
+ },
106
+ {
107
+ "url": "https://hive-api.3speak.tv",
108
+ "version": "1.27.5",
109
+ "type": "appbase",
110
+ "owner": "3speak",
111
+ "hive": True,
112
+ "score": 40,
113
+ },
114
+ {
115
+ "url": "https://hive-api.arcange.eu",
116
+ "version": "1.27.5",
117
+ "type": "appbase",
118
+ "owner": "arcange",
119
+ "hive": True,
120
+ "score": 40,
121
+ },
122
+ {
123
+ "url": "https://hive-api.dlux.io",
124
+ "version": "1.27.8",
125
+ "type": "appbase",
126
+ "owner": "dlux",
127
+ "hive": True,
128
+ "score": 30,
129
+ },
130
+ {
131
+ "url": "https://api.hive.blue",
132
+ "version": "1.27.5",
133
+ "type": "appbase",
134
+ "owner": "hive.blue",
135
+ "hive": True,
136
+ "score": 30,
137
+ },
138
+ {
139
+ "url": "https://hiveapi.actifit.io",
140
+ "version": "1.27.8",
141
+ "type": "appbase",
142
+ "owner": "actifit",
143
+ "hive": True,
144
+ "score": 30,
145
+ },
146
+ {
147
+ "url": "https://techcoderx.com",
148
+ "version": "1.27.7",
149
+ "type": "appbase",
150
+ "owner": "techcoderx",
151
+ "hive": True,
152
+ "score": 20,
153
+ },
154
+ {
155
+ "url": "https://hive-test-beeabode.roelandp.nl",
156
+ "version": "0.23.0",
157
+ "type": "testnet",
158
+ "owner": "roelandp",
159
+ "hive": True,
160
+ "score": 5,
161
+ },
162
+ ]
163
+ super(NodeList, self).__init__(nodes)
164
+
165
+ def update(self, node_list):
166
+ new_nodes = []
167
+ for node_url in node_list:
168
+ node_found = False
169
+ for node in self:
170
+ if node["url"] == node_url:
171
+ new_nodes.append(node)
172
+ node_found = True
173
+ break
174
+ if not node_found:
175
+ log.warning(f"Node {node_url} not found in the original list")
176
+
177
+ super(NodeList, self).__init__(new_nodes)
178
+
179
+ def get_node_answer_time(self, node_list=None, verbose=False):
180
+ """Pings all nodes and measure the answer time
181
+
182
+ .. code-block:: python
183
+
184
+ from nectar.nodelist import NodeList
185
+ nl = NodeList()
186
+ nl.update_nodes()
187
+ nl.ping_nodes()
188
+ """
189
+ ping_times = []
190
+ if node_list is None:
191
+ node_list = []
192
+ for node in self:
193
+ node_list.append(node["url"])
194
+ for node in node_list:
195
+ ping_times.append(1000.0)
196
+ available_nodes = []
197
+ for node in self:
198
+ available_nodes.append(node["url"])
199
+ for i in range(len(node_list)):
200
+ if node_list[i] not in available_nodes:
201
+ ping_times[i] = float("inf")
202
+ continue
203
+ try:
204
+ ping_times[i] = node_answer_time(node_list[i])
205
+ if verbose:
206
+ log.info("node %s results in %.2f" % (node_list[i], ping_times[i]))
207
+ except KeyboardInterrupt:
208
+ ping_times[i] = float("inf")
209
+ break
210
+ sorted_arg = sorted(range(len(ping_times)), key=ping_times.__getitem__)
211
+ sorted_nodes = []
212
+ for i in sorted_arg:
213
+ if ping_times[i] != float("inf"):
214
+ sorted_nodes.append({"url": node_list[i], "delay_ms": ping_times[i] * 1000})
215
+ return sorted_nodes
216
+
217
+ def update_nodes(self, weights=None, blockchain_instance=None, **kwargs):
218
+ """Reads metadata from nectarflower and recalculates the nodes score
219
+
220
+ :param list/dict weight: can be used to weight the different benchmarks
221
+ :type weight: list, dict
222
+
223
+ .. code-block:: python
224
+
225
+ from nectar.nodelist import NodeList
226
+ nl = NodeList()
227
+ weights = [0, 0.1, 0.2, 1]
228
+ nl.update_nodes(weights)
229
+ weights = {'block': 0.1, 'history': 0.1, 'apicall': 1, 'config': 1}
230
+ nl.update_nodes(weights)
231
+ """
232
+ if blockchain_instance is None:
233
+ if kwargs.get("steem_instance"):
234
+ blockchain_instance = kwargs["steem_instance"]
235
+ elif kwargs.get("hive_instance"):
236
+ blockchain_instance = kwargs["hive_instance"]
237
+ steem = blockchain_instance or shared_blockchain_instance()
238
+
239
+ metadata = None
240
+ account = None
241
+ cnt = 0
242
+ while metadata is None and cnt < 5:
243
+ cnt += 1
244
+ try:
245
+ account = Account("nectarflower", blockchain_instance=steem)
246
+ metadata = json.loads(account["posting_json_metadata"])
247
+ except Exception as e:
248
+ log.warning(f"Error fetching metadata (attempt {cnt}): {str(e)}")
249
+ steem.rpc.next()
250
+ account = None
251
+ metadata = None
252
+
253
+ if metadata is None:
254
+ log.warning("Failed to fetch nectarflower metadata after multiple attempts")
255
+ return
256
+
257
+ report = metadata.get("report", [])
258
+ failing_nodes = metadata.get("failing_nodes", {})
259
+ parameter = metadata.get("parameter", {})
260
+ benchmarks = parameter.get("benchmarks", {})
261
+
262
+ # Convert benchmarks dict to list of benchmark names
263
+ benchmark_names = list(benchmarks.keys())
264
+
265
+ if weights is None:
266
+ weights_dict = {}
267
+ for benchmark in benchmark_names:
268
+ weights_dict[benchmark] = 1.0 / len(benchmark_names)
269
+ elif isinstance(weights, list):
270
+ weights_dict = {}
271
+ i = 0
272
+ weight_sum = sum(weights)
273
+ for benchmark in benchmark_names:
274
+ if i < len(weights):
275
+ weights_dict[benchmark] = weights[i] / weight_sum if weight_sum > 0 else 0
276
+ else:
277
+ weights_dict[benchmark] = 0.0
278
+ i += 1
279
+ elif isinstance(weights, dict):
280
+ weights_dict = {}
281
+ weight_sum = sum(weights.values())
282
+ for benchmark in benchmark_names:
283
+ if benchmark in weights:
284
+ weights_dict[benchmark] = (
285
+ weights[benchmark] / weight_sum if weight_sum > 0 else 0
286
+ )
287
+ else:
288
+ weights_dict[benchmark] = 0.0
289
+
290
+ max_score = len(report) + 1
291
+ new_nodes = []
292
+ update_count = 0
293
+ failing_count = 0
294
+
295
+ for node in self:
296
+ new_node = node.copy()
297
+
298
+ # Check against report data
299
+ for report_node in report:
300
+ if node["url"] == report_node.get("node", ""):
301
+ update_count += 1
302
+ new_node["version"] = report_node.get(
303
+ "version", new_node.get("version", "0.0.0")
304
+ )
305
+ new_node["hive"] = report_node.get("hive", new_node.get("hive", False))
306
+
307
+ scores = []
308
+ for benchmark in benchmark_names:
309
+ if benchmark in report_node:
310
+ result = report_node[benchmark]
311
+ rank = result.get("rank", -1)
312
+ if not result.get("ok", False):
313
+ rank = max_score + 1
314
+ score = (
315
+ (max_score - rank) / (max_score - 1) * 100
316
+ if rank > 0 and max_score > 1
317
+ else 0
318
+ )
319
+ weighted_score = score * weights_dict.get(benchmark, 0)
320
+ scores.append(weighted_score)
321
+
322
+ sum_score = sum(scores)
323
+ new_node["score"] = sum_score
324
+ break
325
+
326
+ # Check if node is in failing nodes list
327
+ if node["url"] in failing_nodes:
328
+ failing_count += 1
329
+ new_node["score"] = -1
330
+
331
+ new_nodes.append(new_node)
332
+
333
+ super(NodeList, self).__init__(new_nodes)
334
+
335
+ def get_nodes(
336
+ self,
337
+ hive=False,
338
+ exclude_limited=False,
339
+ dev=False,
340
+ testnet=False,
341
+ testnetdev=False,
342
+ wss=True,
343
+ https=True,
344
+ not_working=False,
345
+ normal=True,
346
+ appbase=True,
347
+ ):
348
+ """Returns nodes as list
349
+
350
+ :param bool hive: When True, only HIVE nodes will be returned
351
+ :param bool exclude_limited: When True, limited nodes are excluded
352
+ :param bool dev: when True, dev nodes with version 0.19.11 are included
353
+ :param bool testnet: when True, testnet nodes are included
354
+ :param bool testnetdev: When True, testnet-dev nodes are included
355
+ :param bool not_working: When True, all nodes including not working ones will be returned
356
+ :param bool normal: deprecated
357
+ :param bool appbase: deprecated
358
+
359
+ """
360
+ node_list = []
361
+ node_type_list = []
362
+ if normal:
363
+ node_type_list.append("normal")
364
+ if appbase:
365
+ node_type_list.append("appbase")
366
+ if dev:
367
+ node_type_list.append("appbase-dev")
368
+ if testnet:
369
+ node_type_list.append("testnet")
370
+ if testnetdev:
371
+ node_type_list.append("testnet-dev")
372
+ if not exclude_limited:
373
+ node_type_list.append("appbase-limited")
374
+ for node in self:
375
+ if node["type"] in node_type_list and (node["score"] >= 0 or not_working):
376
+ if hive != node["hive"]:
377
+ continue
378
+ if not https and node["url"][:5] == "https":
379
+ continue
380
+ if not wss and node["url"][:3] == "wss":
381
+ continue
382
+ node_list.append(node)
383
+
384
+ return [
385
+ node["url"] for node in sorted(node_list, key=lambda self: self["score"], reverse=True)
386
+ ]
387
+
388
+ def get_hive_nodes(self, testnet=False, not_working=False, wss=True, https=True):
389
+ """Returns hive only nodes as list
390
+
391
+ :param bool testnet: when True, testnet nodes are included
392
+ :param bool not_working: When True, all nodes including not working ones will be returned
393
+
394
+ """
395
+ node_list = []
396
+
397
+ for node in self:
398
+ if not node["hive"]:
399
+ continue
400
+ if node["score"] < 0 and not not_working:
401
+ continue
402
+ if (testnet and node["type"] == "testnet") or (
403
+ not testnet and node["type"] != "testnet"
404
+ ):
405
+ if not https and node["url"][:5] == "https":
406
+ continue
407
+ if not wss and node["url"][:3] == "wss":
408
+ continue
409
+ node_list.append(node)
410
+
411
+ return [
412
+ node["url"] for node in sorted(node_list, key=lambda self: self["score"], reverse=True)
413
+ ]
414
+
415
+ def get_steem_nodes(self, testnet=False, not_working=False, wss=True, https=True):
416
+ """Returns steem only nodes as list
417
+
418
+ :param bool testnet: when True, testnet nodes are included
419
+ :param bool not_working: When True, all nodes including not working ones will be returned
420
+
421
+ """
422
+ node_list = []
423
+
424
+ for node in self:
425
+ if node["hive"]:
426
+ continue
427
+ if node["score"] < 0 and not not_working:
428
+ continue
429
+ if (testnet and node["type"] == "testnet") or (
430
+ not testnet and node["type"] != "testnet"
431
+ ):
432
+ if not https and node["url"][:5] == "https":
433
+ continue
434
+ if not wss and node["url"][:3] == "wss":
435
+ continue
436
+ node_list.append(node)
437
+
438
+ return [
439
+ node["url"] for node in sorted(node_list, key=lambda self: self["score"], reverse=True)
440
+ ]
441
+
442
+ def get_testnet(self, testnet=True, testnetdev=False):
443
+ """Returns testnet nodes"""
444
+ return self.get_nodes(normal=False, appbase=False, testnet=testnet, testnetdev=testnetdev)