naeural-client 2.7.27__py3-none-any.whl → 2.7.29__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.
- naeural_client/_ver.py +1 -1
- naeural_client/bc/base.py +112 -221
- naeural_client/bc/ec.py +2 -193
- naeural_client/bc/evm.py +355 -0
- naeural_client/const/base.py +2 -0
- {naeural_client-2.7.27.dist-info → naeural_client-2.7.29.dist-info}/METADATA +1 -1
- {naeural_client-2.7.27.dist-info → naeural_client-2.7.29.dist-info}/RECORD +10 -9
- {naeural_client-2.7.27.dist-info → naeural_client-2.7.29.dist-info}/WHEEL +0 -0
- {naeural_client-2.7.27.dist-info → naeural_client-2.7.29.dist-info}/entry_points.txt +0 -0
- {naeural_client-2.7.27.dist-info → naeural_client-2.7.29.dist-info}/licenses/LICENSE +0 -0
naeural_client/_ver.py
CHANGED
naeural_client/bc/base.py
CHANGED
@@ -7,7 +7,6 @@ import datetime
|
|
7
7
|
import uuid
|
8
8
|
import requests
|
9
9
|
|
10
|
-
from web3 import Web3
|
11
10
|
|
12
11
|
from hashlib import sha256, md5
|
13
12
|
from threading import Lock
|
@@ -24,7 +23,10 @@ from ..const.base import (
|
|
24
23
|
DAUTH_NONCE, dAuth,
|
25
24
|
)
|
26
25
|
|
27
|
-
|
26
|
+
from .evm import _EVMMixin, Web3, EE_VPN_IMPL
|
27
|
+
|
28
|
+
EVM_COMMENT = " # "
|
29
|
+
INVALID_COMMENT = " # INVALID: "
|
28
30
|
|
29
31
|
|
30
32
|
class _DotDict(dict):
|
@@ -238,7 +240,7 @@ def ripemd160(data):
|
|
238
240
|
|
239
241
|
# END ## RIPEMD160
|
240
242
|
|
241
|
-
class BaseBlockEngine:
|
243
|
+
class BaseBlockEngine(_EVMMixin):
|
242
244
|
"""
|
243
245
|
This multiton (multi-singleton via key) is the base workhorse of the private blockchain.
|
244
246
|
|
@@ -326,7 +328,8 @@ class BaseBlockEngine:
|
|
326
328
|
self.__pem_file = pem_fn
|
327
329
|
self._init()
|
328
330
|
return
|
329
|
-
|
331
|
+
|
332
|
+
|
330
333
|
def P(self, s, color=None, boxed=False, verbosity=1, **kwargs):
|
331
334
|
if verbosity > self.__verbosity:
|
332
335
|
return
|
@@ -338,16 +341,36 @@ class BaseBlockEngine:
|
|
338
341
|
boxed=boxed,
|
339
342
|
**kwargs
|
340
343
|
)
|
344
|
+
return
|
341
345
|
|
342
346
|
|
343
347
|
@property
|
344
348
|
def eth_enabled(self):
|
345
349
|
return self.__eth_enabled
|
346
|
-
|
350
|
+
|
351
|
+
|
352
|
+
def set_eth_flag(self, value):
|
353
|
+
if value != self.__eth_enabled:
|
354
|
+
self.__eth_enabled = value
|
355
|
+
self.log.P("Changed eth_enabled to {}".format(value), color='d')
|
356
|
+
return
|
357
|
+
|
358
|
+
|
347
359
|
@property
|
348
360
|
def name(self):
|
349
361
|
return self.__name
|
350
362
|
|
363
|
+
|
364
|
+
@property
|
365
|
+
def eth_address(self):
|
366
|
+
return self.__eth_address
|
367
|
+
|
368
|
+
|
369
|
+
@property
|
370
|
+
def eth_account(self):
|
371
|
+
return self.__eth_account
|
372
|
+
|
373
|
+
|
351
374
|
def _init(self):
|
352
375
|
self.P(
|
353
376
|
f"Initializing BC-engine (ETH_ENABLED={self.__eth_enabled})...", verbosity=1
|
@@ -523,7 +546,7 @@ class BaseBlockEngine:
|
|
523
546
|
return path
|
524
547
|
|
525
548
|
|
526
|
-
def address_is_valid(self, address):
|
549
|
+
def address_is_valid(self, address, return_error=False):
|
527
550
|
"""
|
528
551
|
Checks if an address is valid
|
529
552
|
|
@@ -539,11 +562,15 @@ class BaseBlockEngine:
|
|
539
562
|
|
540
563
|
"""
|
541
564
|
result = False
|
565
|
+
msg = ""
|
542
566
|
try:
|
543
567
|
pk = self._address_to_pk(address)
|
544
568
|
result = False if pk is None else True
|
545
|
-
except:
|
569
|
+
except Exception as exc:
|
546
570
|
result = False
|
571
|
+
msg = str(exc)
|
572
|
+
if return_error:
|
573
|
+
return result, msg
|
547
574
|
return result
|
548
575
|
|
549
576
|
|
@@ -558,8 +585,10 @@ class BaseBlockEngine:
|
|
558
585
|
if isinstance(address, list) and len(address) > 0:
|
559
586
|
# self.P(f"Adding addresses to the allowed list:\n{address}", verbosity=1)
|
560
587
|
# now check addresses
|
561
|
-
|
588
|
+
lst_lines = []
|
589
|
+
lst_addrs = []
|
562
590
|
lst_names = []
|
591
|
+
whitelist = self.whitelist_with_prefixes
|
563
592
|
for addr in address:
|
564
593
|
addr = addr.strip()
|
565
594
|
parts = addr.split()
|
@@ -567,31 +596,45 @@ class BaseBlockEngine:
|
|
567
596
|
continue
|
568
597
|
addr = parts[0]
|
569
598
|
name = parts[1] if len(parts) > 1 else ""
|
570
|
-
|
599
|
+
is_valid, valid_msg = self.address_is_valid(addr, return_error=True)
|
600
|
+
if not is_valid:
|
571
601
|
self.P("WARNING: address <{}> is not valid. Ignoring.".format(addr), color='r')
|
602
|
+
addr = "# " + addr
|
603
|
+
name = name + INVALID_COMMENT + valid_msg
|
604
|
+
continue # skip invalid address or go forward and add it ...
|
572
605
|
else:
|
573
|
-
|
574
|
-
|
606
|
+
addr = self.maybe_add_prefix(addr)
|
607
|
+
if addr in whitelist:
|
608
|
+
self.P("WARNING: address <{}> already in the allowed list. Ignoring.".format(addr), color='r')
|
609
|
+
continue
|
610
|
+
eth = self.node_address_to_eth_address(addr)
|
611
|
+
name = name + EVM_COMMENT + eth
|
612
|
+
str_line = "{}{}".format(addr, (" " + name) if len(name)>0 else "")
|
613
|
+
lst_lines.append(str_line)
|
614
|
+
lst_addrs.append(addr)
|
615
|
+
lst_names.append(name)
|
575
616
|
#endif
|
576
617
|
#endfor
|
577
|
-
if len(
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
618
|
+
if len(lst_lines) > 0:
|
619
|
+
with self._whitelist_lock:
|
620
|
+
fn = self._get_allowed_file()
|
621
|
+
with open(fn, 'rt') as fh:
|
622
|
+
lst_existing = fh.readlines()
|
623
|
+
#endwith
|
624
|
+
for line, addr, name in zip(lst_lines, lst_addrs, lst_names):
|
625
|
+
if line not in lst_existing:
|
583
626
|
changed = True
|
584
|
-
|
585
|
-
|
586
|
-
self.P("Address <{}{}> added to the allowed list.".format(addr, name), color='g')
|
587
|
-
#endif new address
|
627
|
+
lst_existing.append(line)
|
628
|
+
self.P("Address <{}> added to the allowed list.".format(addr), color='g')
|
588
629
|
#endfor
|
589
630
|
if changed:
|
590
631
|
with self._whitelist_lock:
|
591
632
|
fn = self._get_allowed_file()
|
592
633
|
with open(fn, 'wt') as fh:
|
593
|
-
for
|
594
|
-
|
634
|
+
for line in lst_existing:
|
635
|
+
line = line.strip()
|
636
|
+
if line != "":
|
637
|
+
fh.write(f"{line}\n")
|
595
638
|
#endfor each address in modified whitelist
|
596
639
|
#endwith open file
|
597
640
|
#endwith lock
|
@@ -617,30 +660,42 @@ class BaseBlockEngine:
|
|
617
660
|
fh.write('\n')
|
618
661
|
lst_allowed = [x.strip() for x in lst_allowed]
|
619
662
|
lst_allowed = [x for x in lst_allowed if x != '']
|
620
|
-
|
621
|
-
|
663
|
+
lst_lines_to_write = []
|
664
|
+
needs_rewrite = False
|
622
665
|
for allowed_tuple in lst_allowed:
|
623
666
|
parts = allowed_tuple.split()
|
624
667
|
if len(parts) == 0:
|
625
668
|
continue
|
626
669
|
allowed = parts[0]
|
670
|
+
if allowed.startswith("#"):
|
671
|
+
# skip comments but keep them if we re-write the file
|
672
|
+
lst_lines_to_write.append(allowed_tuple)
|
673
|
+
continue
|
627
674
|
allowed = self._remove_prefix(allowed)
|
628
675
|
name = parts[1] if len(parts) > 1 else ""
|
629
|
-
|
630
|
-
|
676
|
+
is_valid, valid_msg = self.address_is_valid(allowed, return_error=True)
|
677
|
+
if not is_valid:
|
678
|
+
self.P("WARNING: address <{}> is not valid. Commenting {} from allowed list.".format(
|
631
679
|
allowed, allowed_tuple), color='r'
|
632
680
|
)
|
633
|
-
|
681
|
+
needs_rewrite = True
|
682
|
+
error_line = "# " + allowed_tuple + INVALID_COMMENT + valid_msg
|
683
|
+
lst_lines_to_write.append(error_line)
|
634
684
|
else:
|
635
685
|
if return_prefix:
|
636
686
|
allowed = self.maybe_add_prefix(allowed)
|
637
687
|
lst_final.append(allowed)
|
638
|
-
lst_lines.append(allowed_tuple)
|
639
688
|
lst_names.append(name)
|
640
|
-
|
689
|
+
if len(parts) < 3:
|
690
|
+
eth = self.node_address_to_eth_address(allowed)
|
691
|
+
allowed_tuple = allowed_tuple + EVM_COMMENT + eth
|
692
|
+
needs_rewrite = True
|
693
|
+
lst_lines_to_write.append(allowed_tuple)
|
694
|
+
|
695
|
+
if needs_rewrite:
|
641
696
|
with open(fn, 'wt') as fh:
|
642
|
-
for line in
|
643
|
-
fh.write("{}\n"
|
697
|
+
for line in lst_lines_to_write:
|
698
|
+
fh.write(f"{line}\n")
|
644
699
|
except Exception as exc:
|
645
700
|
self.P(f"ERROR: failed to load the allowed list of addresses: {exc}", color='r')
|
646
701
|
#endtry
|
@@ -899,32 +954,6 @@ class BaseBlockEngine:
|
|
899
954
|
"""
|
900
955
|
raise NotImplementedError()
|
901
956
|
|
902
|
-
|
903
|
-
def _get_eth_address(self):
|
904
|
-
"""
|
905
|
-
Returns the Ethereum address for the current pk
|
906
|
-
|
907
|
-
Returns
|
908
|
-
-------
|
909
|
-
eth_address : str
|
910
|
-
the Ethereum address.
|
911
|
-
|
912
|
-
"""
|
913
|
-
raise NotImplementedError()
|
914
|
-
|
915
|
-
|
916
|
-
def _get_eth_acccount(self):
|
917
|
-
"""
|
918
|
-
Returns the Ethereum account for the current sk
|
919
|
-
|
920
|
-
Returns
|
921
|
-
-------
|
922
|
-
eth_account : str
|
923
|
-
the Ethereum account.
|
924
|
-
|
925
|
-
"""
|
926
|
-
raise NotImplementedError()
|
927
|
-
|
928
957
|
|
929
958
|
|
930
959
|
#############################################################################
|
@@ -1346,161 +1375,7 @@ class BaseBlockEngine:
|
|
1346
1375
|
raise NotImplementedError()
|
1347
1376
|
|
1348
1377
|
|
1349
|
-
### Ethereum
|
1350
|
-
|
1351
|
-
def set_eth_flag(self, value):
|
1352
|
-
if value != self.__eth_enabled:
|
1353
|
-
self.__eth_enabled = value
|
1354
|
-
self.log.P("Changed eth_enabled to {}".format(value), color='d')
|
1355
|
-
return
|
1356
|
-
|
1357
|
-
@property
|
1358
|
-
def eth_address(self):
|
1359
|
-
return self.__eth_address
|
1360
|
-
|
1361
|
-
@property
|
1362
|
-
def eth_account(self):
|
1363
|
-
return self.__eth_account
|
1364
1378
|
|
1365
|
-
@staticmethod
|
1366
|
-
def is_valid_evm_address(address: str) -> bool:
|
1367
|
-
"""
|
1368
|
-
Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
|
1369
|
-
|
1370
|
-
Parameters
|
1371
|
-
----------
|
1372
|
-
address : str
|
1373
|
-
The address string to verify.
|
1374
|
-
|
1375
|
-
Returns
|
1376
|
-
-------
|
1377
|
-
bool
|
1378
|
-
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
1379
|
-
"""
|
1380
|
-
# Basic checks:
|
1381
|
-
# A) Must start with '0x'
|
1382
|
-
# B) Must be exactly 42 characters in total
|
1383
|
-
# C) All remaining characters must be valid hexadecimal digits
|
1384
|
-
if not address.startswith("0x"):
|
1385
|
-
return False
|
1386
|
-
if len(address) != 42:
|
1387
|
-
return False
|
1388
|
-
|
1389
|
-
hex_part = address[2:]
|
1390
|
-
# Ensure all characters in the hex part are valid hex digits
|
1391
|
-
return all(c in "0123456789abcdefABCDEF" for c in hex_part)
|
1392
|
-
|
1393
|
-
@staticmethod
|
1394
|
-
def is_valid_eth_address(address: str) -> bool:
|
1395
|
-
"""
|
1396
|
-
Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
|
1397
|
-
|
1398
|
-
Parameters
|
1399
|
-
----------
|
1400
|
-
address : str
|
1401
|
-
The address string to verify.
|
1402
|
-
|
1403
|
-
Returns
|
1404
|
-
-------
|
1405
|
-
bool
|
1406
|
-
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
1407
|
-
"""
|
1408
|
-
return BaseBlockEngine.is_valid_evm_address(address)
|
1409
|
-
|
1410
|
-
|
1411
|
-
@staticmethod
|
1412
|
-
def get_evm_network() -> str:
|
1413
|
-
"""
|
1414
|
-
Get the current network
|
1415
|
-
|
1416
|
-
Returns
|
1417
|
-
-------
|
1418
|
-
str
|
1419
|
-
the network name.
|
1420
|
-
|
1421
|
-
"""
|
1422
|
-
return os.environ.get(dAuth.DAUTH_NET_ENV_KEY, dAuth.DAUTH_SDK_NET_DEFAULT)
|
1423
|
-
|
1424
|
-
@property
|
1425
|
-
def evm_network(self):
|
1426
|
-
return self.get_evm_network()
|
1427
|
-
|
1428
|
-
def get_network_data(self, network=None):
|
1429
|
-
assert isinstance(network, str) and network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
|
1430
|
-
return dAuth.EVM_NET_DATA[network.lower()]
|
1431
|
-
|
1432
|
-
|
1433
|
-
def web3_is_node_licensed(self, address : str, network=None, debug=False) -> bool:
|
1434
|
-
"""
|
1435
|
-
Check if the address is allowed to send commands to the node
|
1436
|
-
|
1437
|
-
Parameters
|
1438
|
-
----------
|
1439
|
-
address : str
|
1440
|
-
the address to check.
|
1441
|
-
"""
|
1442
|
-
if network is None:
|
1443
|
-
network = self.evm_network
|
1444
|
-
|
1445
|
-
assert BaseBlockEngine.is_valid_eth_address(address), "Invalid Ethereum address"
|
1446
|
-
|
1447
|
-
network_data = self.get_network_data(network)
|
1448
|
-
|
1449
|
-
contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
|
1450
|
-
rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
1451
|
-
|
1452
|
-
if debug:
|
1453
|
-
self.P(f"Checking if {address} ({network}) is allowed via {rpc_url}...")
|
1454
|
-
|
1455
|
-
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
1456
|
-
|
1457
|
-
contract_abi = dAuth.DAUTH_ABI_IS_NODE_ACTIVE
|
1458
|
-
|
1459
|
-
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
|
1460
|
-
|
1461
|
-
result = contract.functions.isNodeActive(address).call()
|
1462
|
-
return result
|
1463
|
-
|
1464
|
-
|
1465
|
-
def web3_get_oracles(self, network=None, debug=False) -> list:
|
1466
|
-
"""
|
1467
|
-
Get the list of oracles from the contract
|
1468
|
-
|
1469
|
-
Parameters
|
1470
|
-
----------
|
1471
|
-
network : str, optional
|
1472
|
-
the network to use. The default is None.
|
1473
|
-
|
1474
|
-
Returns
|
1475
|
-
-------
|
1476
|
-
list
|
1477
|
-
the list of oracles addresses.
|
1478
|
-
|
1479
|
-
"""
|
1480
|
-
if network is None:
|
1481
|
-
network = BaseBlockEngine.get_evm_network()
|
1482
|
-
|
1483
|
-
network_data = self.get_network_data(network)
|
1484
|
-
|
1485
|
-
contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
|
1486
|
-
rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
1487
|
-
|
1488
|
-
if debug:
|
1489
|
-
self.P(f"Getting oracles for {network} via {rpc_url}...")
|
1490
|
-
|
1491
|
-
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
1492
|
-
|
1493
|
-
contract_abi = dAuth.DAUTH_ABI_GET_SIGNERS
|
1494
|
-
|
1495
|
-
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
|
1496
|
-
|
1497
|
-
result = contract.functions.getSigners().call()
|
1498
|
-
return result
|
1499
|
-
|
1500
|
-
|
1501
|
-
|
1502
|
-
### end Ethereum
|
1503
|
-
|
1504
1379
|
|
1505
1380
|
def dauth_autocomplete(
|
1506
1381
|
self,
|
@@ -1510,6 +1385,7 @@ class BaseBlockEngine:
|
|
1510
1385
|
max_tries=5,
|
1511
1386
|
network=None,
|
1512
1387
|
return_full_data=False,
|
1388
|
+
debug_data=False,
|
1513
1389
|
**kwargs
|
1514
1390
|
):
|
1515
1391
|
"""
|
@@ -1529,6 +1405,9 @@ class BaseBlockEngine:
|
|
1529
1405
|
dict with the dAuth information if the request got status 200(if errors occured, but
|
1530
1406
|
the status is still 200, an empty dictionary will be returned).
|
1531
1407
|
"""
|
1408
|
+
if EE_VPN_IMPL:
|
1409
|
+
return {}
|
1410
|
+
#endif EE_VPN_IMPL
|
1532
1411
|
from naeural_client._ver import __VER__ as sdk_version
|
1533
1412
|
try:
|
1534
1413
|
from ver import __VER__ as app_version
|
@@ -1575,19 +1454,31 @@ class BaseBlockEngine:
|
|
1575
1454
|
while not done:
|
1576
1455
|
self.P(f"<{eth_short}> ({network}) dAuth with `{url}`... (try {tries + 1} / {max_tries})")
|
1577
1456
|
try:
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1457
|
+
if debug_data:
|
1458
|
+
to_send = {
|
1459
|
+
DAUTH_NONCE : str(uuid.uuid4())[:8],
|
1460
|
+
dAuth.DAUTH_SENDER_APP_VER : app_version,
|
1461
|
+
dAuth.DAUTH_SENDER_SDK_VER : sdk_version,
|
1462
|
+
dAuth.DAUTH_SENDER_CORE_VER : core_version,
|
1463
|
+
**kwargs,
|
1464
|
+
}
|
1465
|
+
else:
|
1466
|
+
to_send = {
|
1467
|
+
**kwargs,
|
1468
|
+
DAUTH_NONCE : str(uuid.uuid4())[:8],
|
1469
|
+
dAuth.DAUTH_SENDER_APP_VER : app_version,
|
1470
|
+
dAuth.DAUTH_SENDER_SDK_VER : sdk_version,
|
1471
|
+
dAuth.DAUTH_SENDER_CORE_VER : core_version,
|
1472
|
+
}
|
1585
1473
|
######
|
1586
1474
|
if len(kwargs) == 0:
|
1587
1475
|
to_send[dAuth.DAUTH_SENDER_ALIAS] = dAuth.DAUTH_SENDER_ALIAS_DEFAULT
|
1588
1476
|
######
|
1589
|
-
self.sign(to_send)
|
1590
|
-
|
1477
|
+
self.sign(to_send)
|
1478
|
+
json_to_send = {'body' : to_send}
|
1479
|
+
if debug:
|
1480
|
+
self.P(f"Sending to dAuth URL: {url}\n{json.dumps(json_to_send, indent=2)}")
|
1481
|
+
response = requests.post(url, json=json_to_send)
|
1591
1482
|
if response.status_code == 200:
|
1592
1483
|
dct_response = response.json()
|
1593
1484
|
dct_result = dct_response.get('result', {}) or {}
|
naeural_client/bc/ec.py
CHANGED
@@ -12,11 +12,9 @@ from cryptography.hazmat.backends import default_backend
|
|
12
12
|
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
|
13
13
|
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
|
14
14
|
|
15
|
-
from eth_account import Account
|
16
|
-
from eth_utils import keccak, to_checksum_address
|
17
|
-
from eth_account.messages import encode_defunct
|
18
15
|
|
19
|
-
|
16
|
+
|
17
|
+
from .base import BaseBlockEngine, VerifyMessage, BCct
|
20
18
|
|
21
19
|
|
22
20
|
|
@@ -669,192 +667,3 @@ class BaseBCEllipticCurveEngine(BaseBlockEngine):
|
|
669
667
|
|
670
668
|
## end multi destination encryption
|
671
669
|
|
672
|
-
|
673
|
-
### ETH
|
674
|
-
|
675
|
-
def _get_eth_address(self, pk=None):
|
676
|
-
if pk is None:
|
677
|
-
pk = self.public_key
|
678
|
-
raw_public_key = pk.public_numbers()
|
679
|
-
|
680
|
-
# Compute Ethereum-compatible address
|
681
|
-
x = raw_public_key.x.to_bytes(32, 'big')
|
682
|
-
y = raw_public_key.y.to_bytes(32, 'big')
|
683
|
-
uncompressed_key = b'\x04' + x + y
|
684
|
-
keccak_hash = keccak(uncompressed_key[1:]) # Remove 0x04 prefix
|
685
|
-
eth_address = "0x" + keccak_hash[-20:].hex()
|
686
|
-
eth_address = to_checksum_address(eth_address)
|
687
|
-
return eth_address
|
688
|
-
|
689
|
-
def _get_eth_account(self):
|
690
|
-
private_key_bytes = self.private_key.private_numbers().private_value.to_bytes(32, 'big')
|
691
|
-
return Account.from_key(private_key_bytes)
|
692
|
-
|
693
|
-
|
694
|
-
def node_address_to_eth_address(self, address):
|
695
|
-
"""
|
696
|
-
Converts a node address to an Ethereum address.
|
697
|
-
|
698
|
-
Parameters
|
699
|
-
----------
|
700
|
-
address : str
|
701
|
-
The node address convert.
|
702
|
-
|
703
|
-
Returns
|
704
|
-
-------
|
705
|
-
str
|
706
|
-
The Ethereum address.
|
707
|
-
"""
|
708
|
-
public_key = self._address_to_pk(address)
|
709
|
-
return self._get_eth_address(pk=public_key)
|
710
|
-
|
711
|
-
def is_node_address_in_eth_addresses(self, node_address: str, lst_eth_addrs) -> bool:
|
712
|
-
"""
|
713
|
-
Check if the node address is in the list of Ethereum addresses
|
714
|
-
|
715
|
-
Parameters
|
716
|
-
----------
|
717
|
-
node_address : str
|
718
|
-
the node address.
|
719
|
-
|
720
|
-
lst_eth_addrs : list
|
721
|
-
list of Ethereum addresses.
|
722
|
-
|
723
|
-
Returns
|
724
|
-
-------
|
725
|
-
bool
|
726
|
-
True if the node address is in the list of Ethereum addresses.
|
727
|
-
|
728
|
-
"""
|
729
|
-
eth_addr = self.node_address_to_eth_address(node_address)
|
730
|
-
return eth_addr in lst_eth_addrs
|
731
|
-
|
732
|
-
|
733
|
-
def eth_hash_message(self, types, values, as_hex=False):
|
734
|
-
"""
|
735
|
-
Hashes a message using the keccak256 algorithm.
|
736
|
-
|
737
|
-
Parameters
|
738
|
-
----------
|
739
|
-
types : list
|
740
|
-
The types of the values.
|
741
|
-
|
742
|
-
values : list of any
|
743
|
-
The values to hash.
|
744
|
-
|
745
|
-
Returns
|
746
|
-
-------
|
747
|
-
bytes
|
748
|
-
The hash of the message in hexadecimal format.
|
749
|
-
"""
|
750
|
-
message = Web3.solidity_keccak(types, values)
|
751
|
-
if as_hex:
|
752
|
-
return message.hex()
|
753
|
-
return message
|
754
|
-
|
755
|
-
|
756
|
-
def eth_sign_message(self, types, values):
|
757
|
-
"""
|
758
|
-
Signs a message using the private key.
|
759
|
-
|
760
|
-
Parameters
|
761
|
-
----------
|
762
|
-
types : list
|
763
|
-
The types of the values.
|
764
|
-
|
765
|
-
values : list of any
|
766
|
-
The values to sign.
|
767
|
-
|
768
|
-
Returns
|
769
|
-
-------
|
770
|
-
str
|
771
|
-
The signature of the message.
|
772
|
-
"""
|
773
|
-
message_hash = self.eth_hash_message(types, values, as_hex=False)
|
774
|
-
signable_message = encode_defunct(primitive=message_hash)
|
775
|
-
signed_message = Account.sign_message(signable_message, private_key=self.eth_account.key)
|
776
|
-
if hasattr(signed_message, "message_hash"): # backward compatibility
|
777
|
-
signed_message_hash = signed_message.message_hash
|
778
|
-
else:
|
779
|
-
signed_message_hash = signed_message.messageHash
|
780
|
-
return {
|
781
|
-
"message_hash": message_hash.hex(),
|
782
|
-
"r": hex(signed_message.r),
|
783
|
-
"s": hex(signed_message.s),
|
784
|
-
"v": signed_message.v,
|
785
|
-
"signature": signed_message.signature.hex(),
|
786
|
-
"signed_message": signed_message_hash.hex(),
|
787
|
-
"sender" : self.eth_address,
|
788
|
-
"eth_signed_data" : types,
|
789
|
-
}
|
790
|
-
|
791
|
-
def eth_sign_text(self, message, signature_only=True):
|
792
|
-
"""
|
793
|
-
Signs a text message using the private key.
|
794
|
-
|
795
|
-
Parameters
|
796
|
-
----------
|
797
|
-
message : str
|
798
|
-
The message to sign.
|
799
|
-
|
800
|
-
signature_only : bool, optional
|
801
|
-
Whether to return only the signature. The default is True
|
802
|
-
|
803
|
-
Returns
|
804
|
-
-------
|
805
|
-
str
|
806
|
-
The signature of the message.
|
807
|
-
"""
|
808
|
-
types = ["string"]
|
809
|
-
values = [message]
|
810
|
-
result = self.eth_sign_message(types, values)
|
811
|
-
if signature_only:
|
812
|
-
return result["signature"]
|
813
|
-
return result
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
def eth_sign_node_epochs(
|
818
|
-
self,
|
819
|
-
node,
|
820
|
-
epochs,
|
821
|
-
epochs_vals,
|
822
|
-
signature_only=True,
|
823
|
-
use_evm_node_addr=True
|
824
|
-
):
|
825
|
-
"""
|
826
|
-
Signs the node availability
|
827
|
-
|
828
|
-
Parameters
|
829
|
-
----------
|
830
|
-
node : str
|
831
|
-
The node address to sign. Either the node address or the Ethereum address based on `use_evm_node_addr`.
|
832
|
-
|
833
|
-
epochs : list of int
|
834
|
-
The epochs to sign.
|
835
|
-
|
836
|
-
epochs_vals : list of int
|
837
|
-
The values for each epoch.
|
838
|
-
|
839
|
-
signature_only : bool, optional
|
840
|
-
Whether to return only the signature. The default is True.
|
841
|
-
|
842
|
-
use_evm_node_addr : bool, optional
|
843
|
-
Whether to use the Ethereum address of the node. The default is True.
|
844
|
-
|
845
|
-
Returns
|
846
|
-
-------
|
847
|
-
str
|
848
|
-
The signature of the message.
|
849
|
-
"""
|
850
|
-
if use_evm_node_addr:
|
851
|
-
types = ["address", "uint256[]", "uint256[]"]
|
852
|
-
else:
|
853
|
-
types = ["string", "uint256[]", "uint256[]"]
|
854
|
-
values = [node, epochs, epochs_vals]
|
855
|
-
result = self.eth_sign_message(types, values)
|
856
|
-
if signature_only:
|
857
|
-
return result["signature"]
|
858
|
-
return result
|
859
|
-
|
860
|
-
|
naeural_client/bc/evm.py
ADDED
@@ -0,0 +1,355 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from eth_account import Account
|
4
|
+
from eth_utils import keccak, to_checksum_address
|
5
|
+
from eth_account.messages import encode_defunct
|
6
|
+
|
7
|
+
from ..const.base import EE_VPN_IMPL_ENV_KEY, dAuth
|
8
|
+
|
9
|
+
EE_VPN_IMPL = str(os.environ.get(EE_VPN_IMPL_ENV_KEY, False)).lower() in [
|
10
|
+
'true', '1', 'yes', 'y', 't', 'on'
|
11
|
+
]
|
12
|
+
|
13
|
+
if EE_VPN_IMPL:
|
14
|
+
class Web3:
|
15
|
+
"""
|
16
|
+
VPS enabled. Web3 is not available.
|
17
|
+
"""
|
18
|
+
else:
|
19
|
+
from web3 import Web3
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
class _EVMMixin:
|
24
|
+
|
25
|
+
|
26
|
+
@staticmethod
|
27
|
+
def is_valid_evm_address(address: str) -> bool:
|
28
|
+
"""
|
29
|
+
Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
|
30
|
+
|
31
|
+
Parameters
|
32
|
+
----------
|
33
|
+
address : str
|
34
|
+
The address string to verify.
|
35
|
+
|
36
|
+
Returns
|
37
|
+
-------
|
38
|
+
bool
|
39
|
+
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
40
|
+
"""
|
41
|
+
# Basic checks:
|
42
|
+
# A) Must start with '0x'
|
43
|
+
# B) Must be exactly 42 characters in total
|
44
|
+
# C) All remaining characters must be valid hexadecimal digits
|
45
|
+
if not address.startswith("0x"):
|
46
|
+
return False
|
47
|
+
if len(address) != 42:
|
48
|
+
return False
|
49
|
+
|
50
|
+
hex_part = address[2:]
|
51
|
+
# Ensure all characters in the hex part are valid hex digits
|
52
|
+
return all(c in "0123456789abcdefABCDEF" for c in hex_part)
|
53
|
+
|
54
|
+
@staticmethod
|
55
|
+
def is_valid_eth_address(address: str) -> bool:
|
56
|
+
"""
|
57
|
+
Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
|
58
|
+
|
59
|
+
Parameters
|
60
|
+
----------
|
61
|
+
address : str
|
62
|
+
The address string to verify.
|
63
|
+
|
64
|
+
Returns
|
65
|
+
-------
|
66
|
+
bool
|
67
|
+
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
68
|
+
"""
|
69
|
+
return _EVMMixin.is_valid_evm_address(address)
|
70
|
+
|
71
|
+
|
72
|
+
@staticmethod
|
73
|
+
def get_evm_network() -> str:
|
74
|
+
"""
|
75
|
+
Get the current network
|
76
|
+
|
77
|
+
Returns
|
78
|
+
-------
|
79
|
+
str
|
80
|
+
the network name.
|
81
|
+
|
82
|
+
"""
|
83
|
+
return os.environ.get(dAuth.DAUTH_NET_ENV_KEY, dAuth.DAUTH_SDK_NET_DEFAULT)
|
84
|
+
|
85
|
+
@property
|
86
|
+
def evm_network(self):
|
87
|
+
return self.get_evm_network()
|
88
|
+
|
89
|
+
def get_network_data(self, network=None):
|
90
|
+
assert isinstance(network, str) and network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
|
91
|
+
return dAuth.EVM_NET_DATA[network.lower()]
|
92
|
+
|
93
|
+
|
94
|
+
def web3_is_node_licensed(self, address : str, network=None, debug=False) -> bool:
|
95
|
+
"""
|
96
|
+
Check if the address is allowed to send commands to the node
|
97
|
+
|
98
|
+
Parameters
|
99
|
+
----------
|
100
|
+
address : str
|
101
|
+
the address to check.
|
102
|
+
"""
|
103
|
+
if EE_VPN_IMPL:
|
104
|
+
self.P("VPN implementation. Skipping Ethereum check.", color='r')
|
105
|
+
return False
|
106
|
+
|
107
|
+
if network is None:
|
108
|
+
network = self.evm_network
|
109
|
+
|
110
|
+
assert self.is_valid_eth_address(address), "Invalid Ethereum address"
|
111
|
+
|
112
|
+
network_data = self.get_network_data(network)
|
113
|
+
|
114
|
+
contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
|
115
|
+
rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
116
|
+
|
117
|
+
if debug:
|
118
|
+
self.P(f"Checking if {address} ({network}) is allowed via {rpc_url}...")
|
119
|
+
|
120
|
+
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
121
|
+
|
122
|
+
contract_abi = dAuth.DAUTH_ABI_IS_NODE_ACTIVE
|
123
|
+
|
124
|
+
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
|
125
|
+
|
126
|
+
result = contract.functions.isNodeActive(address).call()
|
127
|
+
return result
|
128
|
+
|
129
|
+
|
130
|
+
def web3_get_oracles(self, network=None, debug=False) -> list:
|
131
|
+
"""
|
132
|
+
Get the list of oracles from the contract
|
133
|
+
|
134
|
+
Parameters
|
135
|
+
----------
|
136
|
+
network : str, optional
|
137
|
+
the network to use. The default is None.
|
138
|
+
|
139
|
+
Returns
|
140
|
+
-------
|
141
|
+
list
|
142
|
+
the list of oracles addresses.
|
143
|
+
|
144
|
+
"""
|
145
|
+
if network is None:
|
146
|
+
network = self.evm_network
|
147
|
+
|
148
|
+
network_data = self.get_network_data(network)
|
149
|
+
|
150
|
+
contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
|
151
|
+
rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
152
|
+
|
153
|
+
if debug:
|
154
|
+
self.P(f"Getting oracles for {network} via {rpc_url}...")
|
155
|
+
|
156
|
+
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
157
|
+
|
158
|
+
contract_abi = dAuth.DAUTH_ABI_GET_SIGNERS
|
159
|
+
|
160
|
+
contract = w3.eth.contract(address=contract_address, abi=contract_abi)
|
161
|
+
|
162
|
+
result = contract.functions.getSigners().call()
|
163
|
+
return result
|
164
|
+
|
165
|
+
|
166
|
+
|
167
|
+
### ETH
|
168
|
+
|
169
|
+
def _get_eth_address(self, pk=None):
|
170
|
+
if pk is None:
|
171
|
+
pk = self.public_key
|
172
|
+
raw_public_key = pk.public_numbers()
|
173
|
+
|
174
|
+
# Compute Ethereum-compatible address
|
175
|
+
x = raw_public_key.x.to_bytes(32, 'big')
|
176
|
+
y = raw_public_key.y.to_bytes(32, 'big')
|
177
|
+
uncompressed_key = b'\x04' + x + y
|
178
|
+
keccak_hash = keccak(uncompressed_key[1:]) # Remove 0x04 prefix
|
179
|
+
eth_address = "0x" + keccak_hash[-20:].hex()
|
180
|
+
eth_address = to_checksum_address(eth_address)
|
181
|
+
return eth_address
|
182
|
+
|
183
|
+
def _get_eth_account(self):
|
184
|
+
private_key_bytes = self.private_key.private_numbers().private_value.to_bytes(32, 'big')
|
185
|
+
return Account.from_key(private_key_bytes)
|
186
|
+
|
187
|
+
|
188
|
+
def node_address_to_eth_address(self, address):
|
189
|
+
"""
|
190
|
+
Converts a node address to an Ethereum address.
|
191
|
+
|
192
|
+
Parameters
|
193
|
+
----------
|
194
|
+
address : str
|
195
|
+
The node address convert.
|
196
|
+
|
197
|
+
Returns
|
198
|
+
-------
|
199
|
+
str
|
200
|
+
The Ethereum address.
|
201
|
+
"""
|
202
|
+
public_key = self._address_to_pk(address)
|
203
|
+
return self._get_eth_address(pk=public_key)
|
204
|
+
|
205
|
+
def is_node_address_in_eth_addresses(self, node_address: str, lst_eth_addrs) -> bool:
|
206
|
+
"""
|
207
|
+
Check if the node address is in the list of Ethereum addresses
|
208
|
+
|
209
|
+
Parameters
|
210
|
+
----------
|
211
|
+
node_address : str
|
212
|
+
the node address.
|
213
|
+
|
214
|
+
lst_eth_addrs : list
|
215
|
+
list of Ethereum addresses.
|
216
|
+
|
217
|
+
Returns
|
218
|
+
-------
|
219
|
+
bool
|
220
|
+
True if the node address is in the list of Ethereum addresses.
|
221
|
+
|
222
|
+
"""
|
223
|
+
eth_addr = self.node_address_to_eth_address(node_address)
|
224
|
+
return eth_addr in lst_eth_addrs
|
225
|
+
|
226
|
+
|
227
|
+
def eth_hash_message(self, types, values, as_hex=False):
|
228
|
+
"""
|
229
|
+
Hashes a message using the keccak256 algorithm.
|
230
|
+
|
231
|
+
Parameters
|
232
|
+
----------
|
233
|
+
types : list
|
234
|
+
The types of the values.
|
235
|
+
|
236
|
+
values : list of any
|
237
|
+
The values to hash.
|
238
|
+
|
239
|
+
Returns
|
240
|
+
-------
|
241
|
+
bytes
|
242
|
+
The hash of the message in hexadecimal format.
|
243
|
+
"""
|
244
|
+
message = Web3.solidity_keccak(types, values)
|
245
|
+
if as_hex:
|
246
|
+
return message.hex()
|
247
|
+
return message
|
248
|
+
|
249
|
+
|
250
|
+
def eth_sign_message(self, types, values):
|
251
|
+
"""
|
252
|
+
Signs a message using the private key.
|
253
|
+
|
254
|
+
Parameters
|
255
|
+
----------
|
256
|
+
types : list
|
257
|
+
The types of the values.
|
258
|
+
|
259
|
+
values : list of any
|
260
|
+
The values to sign.
|
261
|
+
|
262
|
+
Returns
|
263
|
+
-------
|
264
|
+
str
|
265
|
+
The signature of the message.
|
266
|
+
"""
|
267
|
+
message_hash = self.eth_hash_message(types, values, as_hex=False)
|
268
|
+
signable_message = encode_defunct(primitive=message_hash)
|
269
|
+
signed_message = Account.sign_message(signable_message, private_key=self.eth_account.key)
|
270
|
+
if hasattr(signed_message, "message_hash"): # backward compatibility
|
271
|
+
signed_message_hash = signed_message.message_hash
|
272
|
+
else:
|
273
|
+
signed_message_hash = signed_message.messageHash
|
274
|
+
return {
|
275
|
+
"message_hash": message_hash.hex(),
|
276
|
+
"r": hex(signed_message.r),
|
277
|
+
"s": hex(signed_message.s),
|
278
|
+
"v": signed_message.v,
|
279
|
+
"signature": signed_message.signature.hex(),
|
280
|
+
"signed_message": signed_message_hash.hex(),
|
281
|
+
"sender" : self.eth_address,
|
282
|
+
"eth_signed_data" : types,
|
283
|
+
}
|
284
|
+
|
285
|
+
def eth_sign_text(self, message, signature_only=True):
|
286
|
+
"""
|
287
|
+
Signs a text message using the private key.
|
288
|
+
|
289
|
+
Parameters
|
290
|
+
----------
|
291
|
+
message : str
|
292
|
+
The message to sign.
|
293
|
+
|
294
|
+
signature_only : bool, optional
|
295
|
+
Whether to return only the signature. The default is True
|
296
|
+
|
297
|
+
Returns
|
298
|
+
-------
|
299
|
+
str
|
300
|
+
The signature of the message.
|
301
|
+
"""
|
302
|
+
types = ["string"]
|
303
|
+
values = [message]
|
304
|
+
result = self.eth_sign_message(types, values)
|
305
|
+
if signature_only:
|
306
|
+
return result["signature"]
|
307
|
+
return result
|
308
|
+
|
309
|
+
|
310
|
+
|
311
|
+
def eth_sign_node_epochs(
|
312
|
+
self,
|
313
|
+
node,
|
314
|
+
epochs,
|
315
|
+
epochs_vals,
|
316
|
+
signature_only=True,
|
317
|
+
use_evm_node_addr=True
|
318
|
+
):
|
319
|
+
"""
|
320
|
+
Signs the node availability
|
321
|
+
|
322
|
+
Parameters
|
323
|
+
----------
|
324
|
+
node : str
|
325
|
+
The node address to sign. Either the node address or the Ethereum address based on `use_evm_node_addr`.
|
326
|
+
|
327
|
+
epochs : list of int
|
328
|
+
The epochs to sign.
|
329
|
+
|
330
|
+
epochs_vals : list of int
|
331
|
+
The values for each epoch.
|
332
|
+
|
333
|
+
signature_only : bool, optional
|
334
|
+
Whether to return only the signature. The default is True.
|
335
|
+
|
336
|
+
use_evm_node_addr : bool, optional
|
337
|
+
Whether to use the Ethereum address of the node. The default is True.
|
338
|
+
|
339
|
+
Returns
|
340
|
+
-------
|
341
|
+
str
|
342
|
+
The signature of the message.
|
343
|
+
"""
|
344
|
+
if use_evm_node_addr:
|
345
|
+
types = ["address", "uint256[]", "uint256[]"]
|
346
|
+
else:
|
347
|
+
types = ["string", "uint256[]", "uint256[]"]
|
348
|
+
values = [node, epochs, epochs_vals]
|
349
|
+
result = self.eth_sign_message(types, values)
|
350
|
+
if signature_only:
|
351
|
+
return result["signature"]
|
352
|
+
return result
|
353
|
+
|
354
|
+
|
355
|
+
|
naeural_client/const/base.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: naeural_client
|
3
|
-
Version: 2.7.
|
3
|
+
Version: 2.7.29
|
4
4
|
Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
|
5
5
|
Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
|
6
6
|
Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
|
@@ -1,5 +1,5 @@
|
|
1
1
|
naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
|
2
|
-
naeural_client/_ver.py,sha256=
|
2
|
+
naeural_client/_ver.py,sha256=JqBpFIjrfwZRS_X2fLTG2ivMFcGrMcEOLgQ2jSW3iOY,331
|
3
3
|
naeural_client/base_decentra_object.py,sha256=C4iwZTkhKNBS4VHlJs5DfElRYLo4Q9l1V1DNVSk1fyQ,4412
|
4
4
|
naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
|
5
5
|
naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
|
@@ -14,9 +14,10 @@ naeural_client/base/webapp_pipeline.py,sha256=ZNGqZ36DY076XVDfGu2Q61kCt3kxIJ4Mi4
|
|
14
14
|
naeural_client/base/payload/__init__.py,sha256=y8fBI8tG2ObNfaXFWjyWZXwu878FRYj_I8GIbHT4GKE,29
|
15
15
|
naeural_client/base/payload/payload.py,sha256=x-au7l67Z_vfn_4R2C_pjZCaFuUVXHngJiGOfIAYVdE,2690
|
16
16
|
naeural_client/bc/__init__.py,sha256=FQj23D1PrY06NUOARiKQi4cdj0-VxnoYgYDEht8lpr8,158
|
17
|
-
naeural_client/bc/base.py,sha256
|
17
|
+
naeural_client/bc/base.py,sha256=zhfzFFMYSmWB-2KLclvnEF35jobrNLFLIFc4ZvxCcE0,44568
|
18
18
|
naeural_client/bc/chain.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
-
naeural_client/bc/ec.py,sha256
|
19
|
+
naeural_client/bc/ec.py,sha256=FwlkWmJvQ9aHuf_BZX1CWSUAxw6OZ9jBparLIWcs_e4,18933
|
20
|
+
naeural_client/bc/evm.py,sha256=3QwHxU5nOM03OmcxtxaqCBaoft2o-QuAQ-hWD-miKJI,8937
|
20
21
|
naeural_client/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
21
22
|
naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
|
22
23
|
naeural_client/certs/s624dbd4.ala.us-east-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
|
@@ -34,7 +35,7 @@ naeural_client/comm/mqtt_wrapper.py,sha256=Ig3bFZkCbWd4y_Whn2PPa91Z3aLgNbNPau6Tn
|
|
34
35
|
naeural_client/const/README.md,sha256=6OHesr-f5NBuuJGryEoi_TCu2XdlhfQYlDKx_IJoXeg,177
|
35
36
|
naeural_client/const/__init__.py,sha256=MM6Zib6i7M2qWcMkLtLx14zqU-lE-u2uPHjNvbh2jAM,478
|
36
37
|
naeural_client/const/apps.py,sha256=ePBiJXLuPfFOKuw-LJrT9OWbaodU7QApfDurIPNDoB4,655
|
37
|
-
naeural_client/const/base.py,sha256=
|
38
|
+
naeural_client/const/base.py,sha256=zfJyGGdrNz_OA5i_6cQxH2lEeJ4PO3092NrwM_gZ_U8,5670
|
38
39
|
naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
|
39
40
|
naeural_client/const/environment.py,sha256=RpdDhDgB8NgRoFTk28eODigf9y0WcT9lul6mBOD029w,879
|
40
41
|
naeural_client/const/evm_net.py,sha256=mOSvsJnir1v_BrmKS51xIy9ddlZnQwlXWenzGXmXMOE,2606
|
@@ -85,8 +86,8 @@ naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_L
|
|
85
86
|
naeural_client/utils/config.py,sha256=IG7-rRYBWCqCiI2kDesFmY8gld0Ku9xWgzNPE1rwVcA,10352
|
86
87
|
naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
|
87
88
|
naeural_client/utils/oracle_sync/oracle_tester.py,sha256=GmZwu2JM9_UB2K-4rKB3o0RgWLqM-7Im6HwBnQLXmHI,25312
|
88
|
-
naeural_client-2.7.
|
89
|
-
naeural_client-2.7.
|
90
|
-
naeural_client-2.7.
|
91
|
-
naeural_client-2.7.
|
92
|
-
naeural_client-2.7.
|
89
|
+
naeural_client-2.7.29.dist-info/METADATA,sha256=rWf_TRBs9LncFBWUHz9UAWuou8d5U3Y9vWXiXPN0410,12354
|
90
|
+
naeural_client-2.7.29.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
91
|
+
naeural_client-2.7.29.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
|
92
|
+
naeural_client-2.7.29.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
|
93
|
+
naeural_client-2.7.29.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|