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.
- hive_nectar-0.0.2.dist-info/METADATA +182 -0
- hive_nectar-0.0.2.dist-info/RECORD +86 -0
- hive_nectar-0.0.2.dist-info/WHEEL +4 -0
- hive_nectar-0.0.2.dist-info/entry_points.txt +2 -0
- hive_nectar-0.0.2.dist-info/licenses/LICENSE.txt +23 -0
- nectar/__init__.py +32 -0
- nectar/account.py +4371 -0
- nectar/amount.py +475 -0
- nectar/asciichart.py +270 -0
- nectar/asset.py +82 -0
- nectar/block.py +446 -0
- nectar/blockchain.py +1178 -0
- nectar/blockchaininstance.py +2284 -0
- nectar/blockchainobject.py +221 -0
- nectar/blurt.py +563 -0
- nectar/cli.py +6285 -0
- nectar/comment.py +1217 -0
- nectar/community.py +513 -0
- nectar/constants.py +111 -0
- nectar/conveyor.py +309 -0
- nectar/discussions.py +1709 -0
- nectar/exceptions.py +149 -0
- nectar/hive.py +546 -0
- nectar/hivesigner.py +420 -0
- nectar/imageuploader.py +72 -0
- nectar/instance.py +129 -0
- nectar/market.py +1013 -0
- nectar/memo.py +449 -0
- nectar/message.py +357 -0
- nectar/nodelist.py +444 -0
- nectar/price.py +557 -0
- nectar/profile.py +65 -0
- nectar/rc.py +308 -0
- nectar/snapshot.py +726 -0
- nectar/steem.py +582 -0
- nectar/storage.py +53 -0
- nectar/transactionbuilder.py +622 -0
- nectar/utils.py +545 -0
- nectar/version.py +2 -0
- nectar/vote.py +557 -0
- nectar/wallet.py +472 -0
- nectar/witness.py +617 -0
- nectarapi/__init__.py +11 -0
- nectarapi/exceptions.py +123 -0
- nectarapi/graphenerpc.py +589 -0
- nectarapi/node.py +178 -0
- nectarapi/noderpc.py +229 -0
- nectarapi/rpcutils.py +97 -0
- nectarapi/version.py +2 -0
- nectarbase/__init__.py +14 -0
- nectarbase/ledgertransactions.py +75 -0
- nectarbase/memo.py +243 -0
- nectarbase/objects.py +429 -0
- nectarbase/objecttypes.py +22 -0
- nectarbase/operationids.py +102 -0
- nectarbase/operations.py +1297 -0
- nectarbase/signedtransactions.py +48 -0
- nectarbase/transactions.py +11 -0
- nectarbase/version.py +2 -0
- nectargrapheneapi/__init__.py +6 -0
- nectargraphenebase/__init__.py +27 -0
- nectargraphenebase/account.py +846 -0
- nectargraphenebase/aes.py +52 -0
- nectargraphenebase/base58.py +192 -0
- nectargraphenebase/bip32.py +494 -0
- nectargraphenebase/bip38.py +134 -0
- nectargraphenebase/chains.py +149 -0
- nectargraphenebase/dictionary.py +3 -0
- nectargraphenebase/ecdsasig.py +326 -0
- nectargraphenebase/objects.py +123 -0
- nectargraphenebase/objecttypes.py +6 -0
- nectargraphenebase/operationids.py +3 -0
- nectargraphenebase/operations.py +23 -0
- nectargraphenebase/prefix.py +11 -0
- nectargraphenebase/py23.py +38 -0
- nectargraphenebase/signedtransactions.py +201 -0
- nectargraphenebase/types.py +419 -0
- nectargraphenebase/unsignedtransactions.py +283 -0
- nectargraphenebase/version.py +2 -0
- nectarstorage/__init__.py +38 -0
- nectarstorage/base.py +306 -0
- nectarstorage/exceptions.py +16 -0
- nectarstorage/interfaces.py +237 -0
- nectarstorage/masterpassword.py +239 -0
- nectarstorage/ram.py +30 -0
- 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)
|