naeural-client 3.0.8__py3-none-any.whl → 3.1.0__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/base/generic_session.py +22 -3
- naeural_client/bc/base.py +1 -1
- naeural_client/bc/evm.py +728 -302
- naeural_client/cli/nodes.py +2 -0
- naeural_client/const/evm_net.py +4 -0
- {naeural_client-3.0.8.dist-info → naeural_client-3.1.0.dist-info}/METADATA +1 -1
- {naeural_client-3.0.8.dist-info → naeural_client-3.1.0.dist-info}/RECORD +11 -11
- {naeural_client-3.0.8.dist-info → naeural_client-3.1.0.dist-info}/WHEEL +0 -0
- {naeural_client-3.0.8.dist-info → naeural_client-3.1.0.dist-info}/entry_points.txt +0 -0
- {naeural_client-3.0.8.dist-info → naeural_client-3.1.0.dist-info}/licenses/LICENSE +0 -0
naeural_client/_ver.py
CHANGED
@@ -328,7 +328,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
328
328
|
self.__fill_config(
|
329
329
|
host=self.__host,
|
330
330
|
port=self.__port,
|
331
|
-
user=self.
|
331
|
+
user=self.__user,
|
332
332
|
pwd=self.__pwd,
|
333
333
|
secured=self.__secured,
|
334
334
|
)
|
@@ -3000,6 +3000,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
3000
3000
|
|
3001
3001
|
eth: bool, optional
|
3002
3002
|
If True, will use the nodes eth addresses instead of internal. Defaults to False.
|
3003
|
+
It will also display extra info about node wallets (ETH and $R1 balances)
|
3003
3004
|
|
3004
3005
|
all_info: bool, optional
|
3005
3006
|
If True, will return all the information. Defaults to False.
|
@@ -3032,10 +3033,17 @@ class GenericSession(BaseDecentrAIObject):
|
|
3032
3033
|
if all_info:
|
3033
3034
|
mapping = OrderedDict({
|
3034
3035
|
# we assign dummy integer values to the computed columns
|
3035
|
-
# and we will
|
3036
|
+
# and we will filter them
|
3036
3037
|
'ETH Address': 1,
|
3037
3038
|
**mapping
|
3038
3039
|
})
|
3040
|
+
if eth or all_info:
|
3041
|
+
mapping = OrderedDict({
|
3042
|
+
**mapping,
|
3043
|
+
'ETH' : 2,
|
3044
|
+
'$R1' : 3,
|
3045
|
+
})
|
3046
|
+
# end if eth or all_info
|
3039
3047
|
res = OrderedDict()
|
3040
3048
|
for k in mapping:
|
3041
3049
|
res[k] = []
|
@@ -3074,6 +3082,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
3074
3082
|
continue
|
3075
3083
|
for key, column in reverse_mapping.items():
|
3076
3084
|
if isinstance(key, int):
|
3085
|
+
# if the key is an integer, then it is a computed column
|
3077
3086
|
continue
|
3078
3087
|
val = node_info.get(key, None)
|
3079
3088
|
if key == PAYLOAD_DATA.NETMON_LAST_REMOTE_TIME:
|
@@ -3088,16 +3097,26 @@ class GenericSession(BaseDecentrAIObject):
|
|
3088
3097
|
# again self.get_node_alias(best_super) might not work if using the hb data
|
3089
3098
|
best_super_alias = node_info.get(PAYLOAD_DATA.NETMON_EEID, None)
|
3090
3099
|
val = self.bc_engine._add_prefix(val)
|
3100
|
+
add_balance = False
|
3091
3101
|
if all_info:
|
3092
3102
|
val_eth = self.bc_engine.node_address_to_eth_address(val)
|
3093
3103
|
res['ETH Address'].append(val_eth)
|
3104
|
+
eth_addr = val_eth
|
3105
|
+
add_balance = True
|
3094
3106
|
elif eth:
|
3095
3107
|
val = self.bc_engine.node_address_to_eth_address(val)
|
3108
|
+
eth_addr = val
|
3109
|
+
add_balance = True
|
3110
|
+
if add_balance:
|
3111
|
+
eth_balance = self.bc_engine.web3_get_balance_eth(val)
|
3112
|
+
r1_balance = self.bc_engine.web3_get_balance_r1(val)
|
3113
|
+
res['ETH'].append(round(eth_balance,4))
|
3114
|
+
res['$R1'].append(round(r1_balance,4))
|
3096
3115
|
elif key == PAYLOAD_DATA.NETMON_WHITELIST:
|
3097
3116
|
val = client_is_allowed
|
3098
3117
|
elif key in [PAYLOAD_DATA.NETMON_STATUS_KEY, PAYLOAD_DATA.NETMON_NODE_VERSION]:
|
3099
3118
|
val = val.split(' ')[0]
|
3100
|
-
res[column].append(val)
|
3119
|
+
res[column].append(val)
|
3101
3120
|
# end for
|
3102
3121
|
# end if
|
3103
3122
|
pd.options.display.float_format = '{:.1f}'.format
|
naeural_client/bc/base.py
CHANGED
@@ -815,7 +815,7 @@ class BaseBlockEngine(_EVMMixin):
|
|
815
815
|
|
816
816
|
"""
|
817
817
|
if from_file and os.path.isfile(source):
|
818
|
-
self.P("Reading SK from '{}'".format(source), verbosity=
|
818
|
+
self.P("Reading SK from '{}'".format(source), verbosity=2)
|
819
819
|
with open(source, 'rt') as fh:
|
820
820
|
data = fh.read()
|
821
821
|
else:
|
naeural_client/bc/evm.py
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
+
import json
|
1
2
|
import os
|
2
3
|
|
4
|
+
from collections import namedtuple
|
5
|
+
|
3
6
|
from eth_account import Account
|
4
7
|
from eth_utils import keccak, to_checksum_address
|
5
8
|
from eth_account.messages import encode_defunct
|
@@ -10,346 +13,769 @@ EE_VPN_IMPL = str(os.environ.get(EE_VPN_IMPL_ENV_KEY, False)).lower() in [
|
|
10
13
|
'true', '1', 'yes', 'y', 't', 'on'
|
11
14
|
]
|
12
15
|
|
13
|
-
|
16
|
+
Web3Vars = namedtuple("Web3Vars", [
|
17
|
+
"w3", "rpc_url", "nd_contract_address", "r1_contract_address", "network"
|
18
|
+
])
|
19
|
+
|
20
|
+
|
21
|
+
if not EE_VPN_IMPL:
|
22
|
+
from web3 import Web3
|
23
|
+
else:
|
14
24
|
class Web3:
|
15
25
|
"""
|
16
26
|
VPS enabled. Web3 is not available.
|
17
27
|
"""
|
18
|
-
else:
|
19
|
-
from web3 import Web3
|
20
|
-
|
21
28
|
|
29
|
+
# A minimal ERC20 ABI for balanceOf, transfer, and decimals functions.
|
30
|
+
ERC20_ABI = [
|
31
|
+
{
|
32
|
+
"constant": True,
|
33
|
+
"inputs": [{"name": "_owner", "type": "address"}],
|
34
|
+
"name": "balanceOf",
|
35
|
+
"outputs": [{"name": "balance", "type": "uint256"}],
|
36
|
+
"payable": False,
|
37
|
+
"stateMutability": "view",
|
38
|
+
"type": "function"
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"constant": False,
|
42
|
+
"inputs": [
|
43
|
+
{"name": "_to", "type": "address"},
|
44
|
+
{"name": "_value", "type": "uint256"}
|
45
|
+
],
|
46
|
+
"name": "transfer",
|
47
|
+
"outputs": [{"name": "success", "type": "bool"}],
|
48
|
+
"payable": False,
|
49
|
+
"stateMutability": "nonpayable",
|
50
|
+
"type": "function"
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"constant": True,
|
54
|
+
"inputs": [],
|
55
|
+
"name": "decimals",
|
56
|
+
"outputs": [{"name": "", "type": "uint8"}],
|
57
|
+
"payable": False,
|
58
|
+
"stateMutability": "view",
|
59
|
+
"type": "function"
|
60
|
+
}
|
61
|
+
]
|
22
62
|
|
23
63
|
class _EVMMixin:
|
24
64
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
65
|
+
# EVM address methods
|
66
|
+
if True:
|
67
|
+
@staticmethod
|
68
|
+
def is_valid_evm_address(address: str) -> bool:
|
69
|
+
"""
|
70
|
+
Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
|
71
|
+
|
72
|
+
Parameters
|
73
|
+
----------
|
74
|
+
address : str
|
75
|
+
The address string to verify.
|
76
|
+
|
77
|
+
Returns
|
78
|
+
-------
|
79
|
+
bool
|
80
|
+
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
81
|
+
"""
|
82
|
+
# Basic checks:
|
83
|
+
# A) Must start with '0x'
|
84
|
+
# B) Must be exactly 42 characters in total
|
85
|
+
# C) All remaining characters must be valid hexadecimal digits
|
86
|
+
if not address.startswith("0x"):
|
87
|
+
return False
|
88
|
+
if len(address) != 42:
|
89
|
+
return False
|
90
|
+
|
91
|
+
hex_part = address[2:]
|
92
|
+
# Ensure all characters in the hex part are valid hex digits
|
93
|
+
return all(c in "0123456789abcdefABCDEF" for c in hex_part)
|
49
94
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
95
|
+
@staticmethod
|
96
|
+
def is_valid_eth_address(address: str) -> bool:
|
97
|
+
"""
|
98
|
+
Check if the input string is a valid Ethereum (EVM) address using basic heuristics.
|
99
|
+
|
100
|
+
Parameters
|
101
|
+
----------
|
102
|
+
address : str
|
103
|
+
The address string to verify.
|
104
|
+
|
105
|
+
Returns
|
106
|
+
-------
|
107
|
+
bool
|
108
|
+
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
109
|
+
"""
|
110
|
+
return _EVMMixin.is_valid_evm_address(address)
|
111
|
+
|
112
|
+
|
113
|
+
def _get_eth_address(self, pk=None):
|
114
|
+
if pk is None:
|
115
|
+
pk = self.public_key
|
116
|
+
raw_public_key = pk.public_numbers()
|
117
|
+
|
118
|
+
# Compute Ethereum-compatible address
|
119
|
+
x = raw_public_key.x.to_bytes(32, 'big')
|
120
|
+
y = raw_public_key.y.to_bytes(32, 'big')
|
121
|
+
uncompressed_key = b'\x04' + x + y
|
122
|
+
keccak_hash = keccak(uncompressed_key[1:]) # Remove 0x04 prefix
|
123
|
+
eth_address = "0x" + keccak_hash[-20:].hex()
|
124
|
+
eth_address = to_checksum_address(eth_address)
|
125
|
+
return eth_address
|
126
|
+
|
127
|
+
|
128
|
+
def _get_eth_account(self):
|
129
|
+
private_key_bytes = self.private_key.private_numbers().private_value.to_bytes(32, 'big')
|
130
|
+
return Account.from_key(private_key_bytes)
|
131
|
+
|
132
|
+
|
133
|
+
def node_address_to_eth_address(self, address):
|
134
|
+
"""
|
135
|
+
Converts a node address to an Ethereum address.
|
136
|
+
|
137
|
+
Parameters
|
138
|
+
----------
|
139
|
+
address : str
|
140
|
+
The node address convert.
|
141
|
+
|
142
|
+
Returns
|
143
|
+
-------
|
144
|
+
str
|
145
|
+
The Ethereum address.
|
146
|
+
"""
|
147
|
+
public_key = self._address_to_pk(address)
|
148
|
+
return self._get_eth_address(pk=public_key)
|
149
|
+
|
150
|
+
|
151
|
+
def is_node_address_in_eth_addresses(self, node_address: str, lst_eth_addrs) -> bool:
|
152
|
+
"""
|
153
|
+
Check if the node address is in the list of Ethereum addresses
|
154
|
+
|
155
|
+
Parameters
|
156
|
+
----------
|
157
|
+
node_address : str
|
158
|
+
the node address.
|
159
|
+
|
160
|
+
lst_eth_addrs : list
|
161
|
+
list of Ethereum addresses.
|
58
162
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
163
|
+
Returns
|
164
|
+
-------
|
165
|
+
bool
|
166
|
+
True if the node address is in the list of Ethereum addresses.
|
63
167
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
True if `address` meets the basic criteria for an EVM address, False otherwise.
|
68
|
-
"""
|
69
|
-
return _EVMMixin.is_valid_evm_address(address)
|
168
|
+
"""
|
169
|
+
eth_addr = self.node_address_to_eth_address(node_address)
|
170
|
+
return eth_addr in lst_eth_addrs
|
70
171
|
|
71
172
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
173
|
+
# EVM networks
|
174
|
+
if True:
|
175
|
+
def reset_network(self, network: str):
|
176
|
+
assert network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
|
177
|
+
os.environ[dAuth.DAUTH_NET_ENV_KEY] = network
|
178
|
+
return
|
179
|
+
|
180
|
+
def get_evm_network(self) -> str:
|
181
|
+
"""
|
182
|
+
Get the current network
|
183
|
+
|
184
|
+
Returns
|
185
|
+
-------
|
186
|
+
str
|
187
|
+
the network name.
|
188
|
+
|
189
|
+
"""
|
190
|
+
network = os.environ.get(dAuth.DAUTH_NET_ENV_KEY, dAuth.DAUTH_SDK_NET_DEFAULT)
|
191
|
+
if not hasattr(self, "current_evm_network") or self.current_evm_network != network:
|
192
|
+
self.current_evm_network = network
|
193
|
+
network_data = self.get_network_data(network)
|
194
|
+
rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
195
|
+
self.web3 = Web3(Web3.HTTPProvider(rpc_url))
|
196
|
+
self.P(f"Resetting Web3 for {network=} via {rpc_url=}...")
|
197
|
+
return network
|
198
|
+
|
199
|
+
@property
|
200
|
+
def evm_network(self):
|
201
|
+
return self.get_evm_network()
|
76
202
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
203
|
+
|
204
|
+
def get_network_data(self, network: str) -> dict:
|
205
|
+
assert isinstance(network, str) and network.lower() in dAuth.EVM_NET_DATA, f"Invalid network: {network}"
|
206
|
+
return dAuth.EVM_NET_DATA[network.lower()]
|
207
|
+
|
81
208
|
|
82
|
-
|
83
|
-
|
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()]
|
209
|
+
@property
|
210
|
+
def network_rpc(self):
|
211
|
+
return self.get_network_data(self.evm_network)[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
92
212
|
|
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
213
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
the address to check.
|
102
|
-
"""
|
103
|
-
if EE_VPN_IMPL:
|
104
|
-
self.P("VPN implementation. Skipping Ethereum check.", color='r')
|
105
|
-
return False
|
214
|
+
@property
|
215
|
+
def nd_contract_address(self):
|
216
|
+
return self.get_network_data(self.evm_network)[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
|
106
217
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
218
|
+
@property
|
219
|
+
def r1_contract_address(self):
|
220
|
+
return self.get_network_data(self.evm_network)[dAuth.EvmNetData.DAUTH_R1_ADDR_KEY]
|
221
|
+
|
222
|
+
|
223
|
+
def _get_web3_vars(self, network=None) -> Web3Vars:
|
224
|
+
if network is None:
|
225
|
+
network = self.evm_network
|
226
|
+
w3 = self.web3
|
227
|
+
rpc_url = self.network_rpc
|
228
|
+
nd_contract_address = self.nd_contract_address
|
229
|
+
r1_contract_address = self.r1_contract_address
|
230
|
+
else:
|
231
|
+
network_data = self.get_network_data(network)
|
232
|
+
nd_contract_address = network_data[dAuth.EvmNetData.DAUTH_ND_ADDR_KEY]
|
233
|
+
rpc_url = network_data[dAuth.EvmNetData.DAUTH_RPC_KEY]
|
234
|
+
r1_contract_address = network_data[dAuth.EvmNetData.DAUTH_R1_ADDR_KEY]
|
235
|
+
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
236
|
+
self.P(f"Created temporary Web3 for {network=} via {rpc_url=}...", verbosity=2)
|
237
|
+
result = Web3Vars(
|
238
|
+
w3=w3, rpc_url=rpc_url, nd_contract_address=nd_contract_address,
|
239
|
+
r1_contract_address=r1_contract_address, network=network
|
240
|
+
)
|
241
|
+
return result
|
242
|
+
|
243
|
+
|
244
|
+
# EVM signing methods (internal)
|
245
|
+
if True:
|
246
|
+
def eth_hash_message(self, types, values, as_hex=False):
|
247
|
+
"""
|
248
|
+
Hashes a message using the keccak256 algorithm.
|
249
|
+
|
250
|
+
Parameters
|
251
|
+
----------
|
252
|
+
types : list
|
253
|
+
The types of the values.
|
254
|
+
|
255
|
+
values : list of any
|
256
|
+
The values to hash.
|
257
|
+
|
258
|
+
Returns
|
259
|
+
-------
|
260
|
+
bytes
|
261
|
+
The hash of the message in hexadecimal format.
|
262
|
+
"""
|
263
|
+
message = Web3.solidity_keccak(types, values)
|
264
|
+
if as_hex:
|
265
|
+
return message.hex()
|
266
|
+
return message
|
111
267
|
|
112
|
-
network_data = self.get_network_data(network)
|
113
268
|
|
114
|
-
|
115
|
-
|
269
|
+
def eth_sign_message(self, types, values):
|
270
|
+
"""
|
271
|
+
Signs a message using the private key.
|
272
|
+
|
273
|
+
Parameters
|
274
|
+
----------
|
275
|
+
types : list
|
276
|
+
The types of the values.
|
116
277
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
w3 = Web3(Web3.HTTPProvider(rpc_url))
|
121
|
-
|
122
|
-
contract_abi = dAuth.DAUTH_ABI_IS_NODE_ACTIVE
|
278
|
+
values : list of any
|
279
|
+
The values to sign.
|
123
280
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
281
|
+
Returns
|
282
|
+
-------
|
283
|
+
str
|
284
|
+
The signature of the message.
|
285
|
+
|
286
|
+
Notes
|
287
|
+
-----
|
288
|
+
|
289
|
+
This function is using the `eth_account` property generated from the private key via
|
290
|
+
the `_get_eth_account` method at the time of the object creation.
|
291
|
+
"""
|
292
|
+
message_hash = self.eth_hash_message(types, values, as_hex=False)
|
293
|
+
signable_message = encode_defunct(primitive=message_hash)
|
294
|
+
signed_message = Account.sign_message(signable_message, private_key=self.eth_account.key)
|
295
|
+
if hasattr(signed_message, "message_hash"): # backward compatibility
|
296
|
+
signed_message_hash = signed_message.message_hash
|
297
|
+
else:
|
298
|
+
signed_message_hash = signed_message.messageHash
|
299
|
+
return {
|
300
|
+
"message_hash": message_hash.hex(),
|
301
|
+
"r": hex(signed_message.r),
|
302
|
+
"s": hex(signed_message.s),
|
303
|
+
"v": signed_message.v,
|
304
|
+
"signature": signed_message.signature.hex(),
|
305
|
+
"signed_message": signed_message_hash.hex(),
|
306
|
+
"sender" : self.eth_address,
|
307
|
+
"eth_signed_data" : types,
|
308
|
+
}
|
309
|
+
|
310
|
+
def eth_sign_text(self, message, signature_only=True):
|
311
|
+
"""
|
312
|
+
Signs a text message using the private key.
|
313
|
+
|
314
|
+
Parameters
|
315
|
+
----------
|
316
|
+
message : str
|
317
|
+
The message to sign.
|
318
|
+
|
319
|
+
signature_only : bool, optional
|
320
|
+
Whether to return only the signature. The default is True
|
321
|
+
|
322
|
+
Returns
|
323
|
+
-------
|
324
|
+
str
|
325
|
+
The signature of the message.
|
326
|
+
"""
|
327
|
+
types = ["string"]
|
328
|
+
values = [message]
|
329
|
+
result = self.eth_sign_message(types, values)
|
330
|
+
if signature_only:
|
331
|
+
return result["signature"]
|
332
|
+
return result
|
333
|
+
|
334
|
+
|
335
|
+
|
336
|
+
def eth_sign_node_epochs(
|
337
|
+
self,
|
338
|
+
node,
|
339
|
+
epochs,
|
340
|
+
epochs_vals,
|
341
|
+
signature_only=True,
|
342
|
+
use_evm_node_addr=True
|
343
|
+
):
|
344
|
+
"""
|
345
|
+
Signs the node availability
|
346
|
+
|
347
|
+
Parameters
|
348
|
+
----------
|
349
|
+
node : str
|
350
|
+
The node address to sign. Either the node address or the Ethereum address based on `use_evm_node_addr`.
|
351
|
+
|
352
|
+
epochs : list of int
|
353
|
+
The epochs to sign.
|
354
|
+
|
355
|
+
epochs_vals : list of int
|
356
|
+
The values for each epoch.
|
357
|
+
|
358
|
+
signature_only : bool, optional
|
359
|
+
Whether to return only the signature. The default is True.
|
360
|
+
|
361
|
+
use_evm_node_addr : bool, optional
|
362
|
+
Whether to use the Ethereum address of the node. The default is True.
|
363
|
+
|
364
|
+
Returns
|
365
|
+
-------
|
366
|
+
str
|
367
|
+
The signature of the message.
|
368
|
+
"""
|
369
|
+
if use_evm_node_addr:
|
370
|
+
types = ["address", "uint256[]", "uint256[]"]
|
371
|
+
else:
|
372
|
+
types = ["string", "uint256[]", "uint256[]"]
|
373
|
+
values = [node, epochs, epochs_vals]
|
374
|
+
result = self.eth_sign_message(types, values)
|
375
|
+
if signature_only:
|
376
|
+
return result["signature"]
|
377
|
+
return result
|
149
378
|
|
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
379
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
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.
|
380
|
+
### Web3 functions
|
381
|
+
if True:
|
382
|
+
def web3_hash_message(self, types, values, as_hex=False):
|
383
|
+
"""
|
384
|
+
Hashes a message using the keccak256 algorithm.
|
385
|
+
|
386
|
+
Parameters
|
387
|
+
----------
|
388
|
+
types : list
|
389
|
+
The types of the values.
|
390
|
+
|
391
|
+
values : list of any
|
392
|
+
The values to hash.
|
393
|
+
|
394
|
+
Returns
|
395
|
+
-------
|
396
|
+
bytes
|
397
|
+
The hash of the message in hexadecimal format.
|
398
|
+
"""
|
399
|
+
return self.eth_hash_message(types, values, as_hex=as_hex)
|
400
|
+
|
401
|
+
def web3_sign_message(self, types, values):
|
402
|
+
"""
|
403
|
+
Signs a message using the private key.
|
404
|
+
|
405
|
+
Parameters
|
406
|
+
----------
|
407
|
+
types : list
|
408
|
+
The types of the values.
|
409
|
+
|
410
|
+
values : list of any
|
411
|
+
The values to sign.
|
196
412
|
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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
|
413
|
+
Returns
|
414
|
+
-------
|
415
|
+
str
|
416
|
+
The signature of the message.
|
417
|
+
|
418
|
+
Notes
|
419
|
+
-----
|
208
420
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
421
|
+
"""
|
422
|
+
return self.eth_sign_message(types, values)
|
423
|
+
|
424
|
+
def web3_is_node_licensed(self, address : str, network=None, debug=False) -> bool:
|
425
|
+
"""
|
426
|
+
Check if the address is allowed to send commands to the node
|
427
|
+
|
428
|
+
Parameters
|
429
|
+
----------
|
430
|
+
address : str
|
431
|
+
the address to check.
|
432
|
+
"""
|
433
|
+
if EE_VPN_IMPL:
|
434
|
+
self.P("VPN implementation. Skipping Ethereum check.", color='r')
|
435
|
+
return False
|
213
436
|
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
437
|
+
w3vars = self._get_web3_vars(network)
|
438
|
+
|
439
|
+
assert self.is_valid_eth_address(address), "Invalid Ethereum address"
|
440
|
+
|
441
|
+
if debug:
|
442
|
+
self.P(f"Checking if {address} ({network}) is allowed...")
|
443
|
+
|
444
|
+
contract_abi = dAuth.DAUTH_ABI_IS_NODE_ACTIVE
|
445
|
+
contract = w3vars.w3.eth.contract(address=w3vars.nd_contract_address, abi=contract_abi)
|
221
446
|
|
222
|
-
|
223
|
-
|
224
|
-
return eth_addr in lst_eth_addrs
|
447
|
+
result = contract.functions.isNodeActive(address).call()
|
448
|
+
return result
|
225
449
|
|
226
450
|
|
227
|
-
|
228
|
-
|
229
|
-
|
451
|
+
def web3_get_oracles(self, network=None, debug=False) -> list:
|
452
|
+
"""
|
453
|
+
Get the list of oracles from the contract
|
230
454
|
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
The
|
235
|
-
|
236
|
-
values : list of any
|
237
|
-
The values to hash.
|
455
|
+
Parameters
|
456
|
+
----------
|
457
|
+
network : str, optional
|
458
|
+
the network to use. The default is None.
|
238
459
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
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.
|
460
|
+
Returns
|
461
|
+
-------
|
462
|
+
list
|
463
|
+
the list of oracles addresses.
|
253
464
|
|
254
|
-
|
255
|
-
|
256
|
-
types : list
|
257
|
-
The types of the values.
|
258
|
-
|
259
|
-
values : list of any
|
260
|
-
The values to sign.
|
465
|
+
"""
|
466
|
+
w3vars = self._get_web3_vars(network)
|
261
467
|
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
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.
|
468
|
+
if debug:
|
469
|
+
self.P(f"Getting oracles for {w3vars.network} via {w3vars.rpc_url}...")
|
470
|
+
|
471
|
+
contract_abi = dAuth.DAUTH_ABI_GET_SIGNERS
|
472
|
+
contract = w3vars.w3.eth.contract(
|
473
|
+
address=w3vars.nd_contract_address, abi=contract_abi
|
474
|
+
)
|
288
475
|
|
289
|
-
|
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
|
476
|
+
result = contract.functions.getSigners().call()
|
477
|
+
return result
|
296
478
|
|
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
479
|
|
480
|
+
def web3_get_balance_eth(self, address=None, network=None):
|
481
|
+
"""
|
482
|
+
Get the ETH balance of the address
|
483
|
+
|
484
|
+
Parameters
|
485
|
+
----------
|
486
|
+
address : str
|
487
|
+
The address to check.
|
488
|
+
|
489
|
+
Returns
|
490
|
+
-------
|
491
|
+
float
|
492
|
+
The balance of the address.
|
493
|
+
"""
|
494
|
+
if address is None:
|
495
|
+
address = self.eth_address
|
496
|
+
assert self.is_valid_eth_address(address), "Invalid Ethereum address"
|
497
|
+
w3vars = self._get_web3_vars(network)
|
498
|
+
balance_wei = w3vars.w3.eth.get_balance(address)
|
499
|
+
balance_eth = w3vars.w3.from_wei(balance_wei, 'ether')
|
500
|
+
return float(balance_eth)
|
501
|
+
|
502
|
+
|
503
|
+
def web3_send_eth(
|
504
|
+
self,
|
505
|
+
to_address,
|
506
|
+
amount_eth,
|
507
|
+
extra_buffer_eth=0.005,
|
508
|
+
network=None,
|
509
|
+
wait_for_tx=True,
|
510
|
+
timeout=120,
|
511
|
+
return_receipt=False,
|
512
|
+
raise_if_error=False,
|
513
|
+
):
|
514
|
+
"""
|
515
|
+
Send ETH from the account associated with this object to another address,
|
516
|
+
ensuring there is enough balance to cover the transfer amount, gas costs,
|
517
|
+
and an additional buffer.
|
518
|
+
|
519
|
+
Parameters
|
520
|
+
----------
|
521
|
+
to_address : str
|
522
|
+
The recipient Ethereum address.
|
523
|
+
|
524
|
+
amount_eth : float
|
525
|
+
The amount of ETH to send.
|
526
|
+
|
527
|
+
extra_buffer_eth : float, optional
|
528
|
+
An additional amount (in ETH) as a safety margin. Default is 0.005 ETH.
|
529
|
+
|
530
|
+
network : str, optional
|
531
|
+
The network to use. Default is None.
|
532
|
+
|
533
|
+
wait_for_tx : bool, optional
|
534
|
+
Whether to wait for the transaction to be mined. Default is True.
|
535
|
+
|
536
|
+
timeout : int, optional
|
537
|
+
The maximum time to wait for the transaction to be mined, in seconds. Default is 120 seconds.
|
538
|
+
|
539
|
+
return_receipt : bool, optional
|
540
|
+
If True, returns the transaction receipt instead of the transaction hash. Default is False.
|
541
|
+
|
542
|
+
raise_if_error : bool, optional
|
543
|
+
If True, raises an exception if the transaction fails. Default is False.
|
544
|
+
|
545
|
+
Returns
|
546
|
+
-------
|
547
|
+
str
|
548
|
+
The transaction hash of the broadcasted transaction.
|
549
|
+
"""
|
550
|
+
w3vars = self._get_web3_vars(network=network)
|
551
|
+
network = w3vars.network
|
552
|
+
|
553
|
+
# Get the sender's address from the object's stored attribute (assumed available)
|
554
|
+
from_address = self.eth_address
|
555
|
+
|
556
|
+
# Fetch the current balance (in Wei)
|
557
|
+
balance_wei = w3vars.w3.eth.get_balance(from_address)
|
558
|
+
|
559
|
+
# Define gas parameters for a standard ETH transfer.
|
560
|
+
gas_limit = 21000 # typical gas limit for a simple ETH transfer
|
561
|
+
gas_price = w3vars.w3.to_wei('50', 'gwei') # example gas price; you may choose a dynamic approach
|
562
|
+
|
563
|
+
# Calculate the total gas cost.
|
564
|
+
gas_cost = gas_limit * gas_price
|
565
|
+
|
566
|
+
# Convert transfer amount and buffer to Wei.
|
567
|
+
amount_wei = w3vars.w3.to_wei(amount_eth, 'ether')
|
568
|
+
extra_buffer = w3vars.w3.to_wei(extra_buffer_eth, 'ether')
|
569
|
+
|
570
|
+
# Compute the total cost: amount to send + gas cost + extra buffer.
|
571
|
+
total_cost = amount_wei + gas_cost + extra_buffer
|
572
|
+
|
573
|
+
# Check if the balance is sufficient.
|
574
|
+
if balance_wei < total_cost:
|
575
|
+
msg = "Insufficient funds: your balance is less than the required amount plus gas cost and buffer."
|
576
|
+
if raise_if_error:
|
577
|
+
raise Exception(msg)
|
578
|
+
else:
|
579
|
+
self.P(msg, color='r')
|
580
|
+
return None
|
581
|
+
|
582
|
+
# Get the nonce for the transaction.
|
583
|
+
nonce = w3vars.w3.eth.get_transaction_count(from_address)
|
584
|
+
|
585
|
+
chain_id = w3vars.w3.eth.chain_id
|
586
|
+
|
587
|
+
# Build the transaction dictionary.
|
588
|
+
tx = {
|
589
|
+
'nonce': nonce,
|
590
|
+
'to': to_address,
|
591
|
+
'value': amount_wei,
|
592
|
+
'gas': gas_limit,
|
593
|
+
'gasPrice': gas_price,
|
594
|
+
'chainId': chain_id,
|
595
|
+
}
|
596
|
+
|
597
|
+
self.P(f"Executing transaction on {network} via {w3vars.rpc_url}:\n {json.dumps(tx, indent=2)}", verbosity=2)
|
598
|
+
|
599
|
+
# Sign the transaction with the account's private key.
|
600
|
+
signed_tx = w3vars.w3.eth.account.sign_transaction(tx, self.eth_account.key)
|
601
|
+
|
602
|
+
# Broadcast the signed transaction.
|
603
|
+
tx_hash = w3vars.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
|
604
|
+
|
605
|
+
if wait_for_tx:
|
606
|
+
# Wait for the transaction receipt with the specified timeout.
|
607
|
+
self.P("Waiting for transaction to be mined...", verbosity=2)
|
608
|
+
tx_receipt = w3vars.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout)
|
609
|
+
tx_hash_hex = tx_receipt.transactionHash.hex()
|
610
|
+
self.P(f"Transaction mined: {tx_hash_hex}", color='g', verbosity=2)
|
611
|
+
if return_receipt:
|
612
|
+
return tx_receipt
|
613
|
+
else:
|
614
|
+
return tx_hash_hex
|
615
|
+
else:
|
616
|
+
return tx_hash.hex()
|
617
|
+
|
618
|
+
|
619
|
+
def web3_get_balance_r1(self, address=None, network=None):
|
620
|
+
"""
|
621
|
+
Get the R1 balance of the address
|
622
|
+
|
623
|
+
Parameters
|
624
|
+
----------
|
625
|
+
address : str
|
626
|
+
The address to check.
|
627
|
+
|
628
|
+
Returns
|
629
|
+
-------
|
630
|
+
float
|
631
|
+
The balance of the address.
|
632
|
+
"""
|
633
|
+
if address is None:
|
634
|
+
address = self.eth_address
|
635
|
+
assert self.is_valid_eth_address(address), "Invalid Ethereum address"
|
636
|
+
w3vars = self._get_web3_vars(network)
|
637
|
+
|
638
|
+
token_contract = w3vars.w3.eth.contract(
|
639
|
+
address=w3vars.r1_contract_address, abi=ERC20_ABI
|
640
|
+
)
|
641
|
+
|
642
|
+
try:
|
643
|
+
decimals = token_contract.functions.decimals().call()
|
644
|
+
except Exception:
|
645
|
+
decimals = 18 # default to 18 if the decimals call fails
|
646
|
+
|
647
|
+
raw_balance = token_contract.functions.balanceOf(address).call()
|
648
|
+
human_balance = raw_balance / (10 ** decimals)
|
649
|
+
return float(human_balance)
|
310
650
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
651
|
+
def web3_send_r1(
|
652
|
+
self,
|
653
|
+
to_address: str,
|
654
|
+
amount: float,
|
655
|
+
extra_buffer_eth: float = 0.005,
|
656
|
+
wait_for_tx: bool = False,
|
657
|
+
timeout: int = 120,
|
658
|
+
network: str = None,
|
659
|
+
return_receipt=False,
|
660
|
+
raise_if_error=False,
|
661
|
+
):
|
662
|
+
"""
|
663
|
+
Send R1 tokens from the default account (self.eth_address) to the specified address.
|
664
|
+
|
665
|
+
Parameters
|
666
|
+
----------
|
667
|
+
to_address : str
|
668
|
+
The recipient's Ethereum address.
|
669
|
+
|
670
|
+
amount : float
|
671
|
+
The amount of R1 tokens to send (in human-readable units).
|
672
|
+
|
673
|
+
extra_buffer_eth : float, optional
|
674
|
+
Additional ETH (in Ether) as a buffer for gas fees. Default is 0.005 ETH.
|
675
|
+
|
676
|
+
wait_for_tx : bool, optional
|
677
|
+
If True, waits for the transaction to be mined and returns the receipt.
|
678
|
+
If False, returns immediately with the transaction hash.
|
679
|
+
|
680
|
+
timeout : int, optional
|
681
|
+
Maximum number of seconds to wait for the transaction receipt. Default is 120.
|
682
|
+
|
683
|
+
network : str, optional
|
684
|
+
The network to use. If None, uses the default self.evm_network.
|
321
685
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
686
|
+
return_receipt: bool, optional
|
687
|
+
If True, returns the transaction receipt instead of the transaction hash.
|
688
|
+
|
689
|
+
raise_if_error : bool, optional
|
690
|
+
If True, raises an exception if the transaction fails. Default is False.
|
691
|
+
|
692
|
+
Returns
|
693
|
+
-------
|
694
|
+
If wait_for_tx is False, returns the transaction hash as a string.
|
695
|
+
If wait_for_tx is True, returns the transaction receipt as a dict.
|
696
|
+
"""
|
697
|
+
# Validate the recipient address.
|
698
|
+
assert self.is_valid_eth_address(to_address), "Invalid Ethereum address"
|
699
|
+
|
700
|
+
# Retrieve the Web3 instance, RPC URL, and the R1 contract address.
|
701
|
+
# Note: This follows the same pattern as web3_get_balance_r1.
|
702
|
+
w3vars = self._get_web3_vars(network)
|
703
|
+
network = w3vars.network
|
704
|
+
|
705
|
+
# Create the token contract instance.
|
706
|
+
token_contract = w3vars.w3.eth.contract(
|
707
|
+
address=w3vars.r1_contract_address, abi=ERC20_ABI
|
708
|
+
)
|
709
|
+
|
710
|
+
# Get the token's decimals (default to 18 if not available).
|
711
|
+
try:
|
712
|
+
decimals = token_contract.functions.decimals().call()
|
713
|
+
except Exception:
|
714
|
+
decimals = 18
|
715
|
+
|
716
|
+
# Convert the human-readable amount to the token's smallest unit.
|
717
|
+
token_amount = int(amount * (10 ** decimals))
|
718
|
+
|
719
|
+
# Ensure the sender has enough R1 token balance.
|
720
|
+
sender_balance = token_contract.functions.balanceOf(self.eth_address).call()
|
721
|
+
if sender_balance < token_amount:
|
722
|
+
msg = "Insufficient funds: your $R1 balance is less than the required amount."
|
723
|
+
if raise_if_error:
|
724
|
+
raise Exception(msg)
|
725
|
+
else:
|
726
|
+
self.P(msg, color='r')
|
727
|
+
return None
|
728
|
+
|
729
|
+
# Estimate gas fees for the token transfer.
|
730
|
+
gas_price = w3vars.w3.to_wei('50', 'gwei') # Adjust as needed or use a dynamic gas strategy.
|
731
|
+
estimated_gas = token_contract.functions.transfer(
|
732
|
+
to_address, token_amount
|
733
|
+
).estimate_gas(
|
734
|
+
{'from': self.eth_address}
|
735
|
+
)
|
736
|
+
gas_cost = estimated_gas * gas_price
|
737
|
+
|
738
|
+
# Check that the sender's ETH balance can cover gas costs plus an extra buffer.
|
739
|
+
eth_balance = w3vars.w3.eth.get_balance(self.eth_address)
|
740
|
+
extra_buffer = w3vars.w3.to_wei(extra_buffer_eth, 'ether')
|
741
|
+
if eth_balance < gas_cost + extra_buffer:
|
742
|
+
raise Exception("Insufficient ETH balance to cover gas fees and extra buffer.")
|
743
|
+
|
744
|
+
# Get the transaction count for the nonce.
|
745
|
+
nonce = w3vars.w3.eth.get_transaction_count(self.eth_address)
|
746
|
+
|
747
|
+
# Programmatically determine the chainId.
|
748
|
+
chain_id = w3vars.w3.eth.chain_id
|
749
|
+
|
750
|
+
# Build the transaction for the ERC20 transfer.
|
751
|
+
tx = token_contract.functions.transfer(to_address, token_amount).build_transaction({
|
752
|
+
'from': self.eth_address,
|
753
|
+
'nonce': nonce,
|
754
|
+
'gas': estimated_gas,
|
755
|
+
'gasPrice': gas_price,
|
756
|
+
'chainId': chain_id,
|
757
|
+
})
|
758
|
+
|
759
|
+
self.P(f"Executing transaction on {network} via {w3vars.rpc_url}:\n {json.dumps(dict(tx), indent=2)}", verbosity=2)
|
760
|
+
|
761
|
+
# Sign the transaction using the internal account (via _get_eth_account).
|
762
|
+
eth_account = self._get_eth_account()
|
763
|
+
signed_tx = w3vars.w3.eth.account.sign_transaction(tx, eth_account.key)
|
764
|
+
|
765
|
+
# Broadcast the transaction.
|
766
|
+
tx_hash = w3vars.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
|
767
|
+
|
768
|
+
if wait_for_tx:
|
769
|
+
# Wait for the transaction receipt if required.
|
770
|
+
tx_receipt = w3vars.w3.eth.wait_for_transaction_receipt(tx_hash, timeout=timeout)
|
771
|
+
tx_hash_hex = tx_receipt.transactionHash.hex()
|
772
|
+
self.P(f"Transaction mined: {tx_hash_hex}", color='g', verbosity=2)
|
773
|
+
if return_receipt:
|
774
|
+
return tx_receipt
|
775
|
+
else:
|
776
|
+
return tx_hash_hex
|
777
|
+
else:
|
778
|
+
return tx_hash.hex()
|
338
779
|
|
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
780
|
|
355
|
-
|
781
|
+
|
naeural_client/cli/nodes.py
CHANGED
@@ -76,6 +76,8 @@ def get_nodes(args):
|
|
76
76
|
log_with_color(f"No supervisors or no comms available in {elapsed:.1f}s. Please check your settings.", color='r')
|
77
77
|
else:
|
78
78
|
log_with_color(f"<{network}> {prefix}odes reported by <{supervisor}> '{super_alias}' in {elapsed:.1f}s ({nr_supers} supervisors seen):", color='b')
|
79
|
+
import pandas as pd
|
80
|
+
pd.set_option('display.float_format', '{:.4f}'.format)
|
79
81
|
log_with_color(f"{df}")
|
80
82
|
return
|
81
83
|
|
naeural_client/const/evm_net.py
CHANGED
@@ -2,6 +2,7 @@ class EvmNetData:
|
|
2
2
|
DAUTH_URL_KEY = 'EE_DAUTH_URL'
|
3
3
|
DAUTH_ND_ADDR_KEY = 'EE_DAUTH_ND_ADDR'
|
4
4
|
DAUTH_RPC_KEY = 'EE_DAUTH_RPC'
|
5
|
+
DAUTH_R1_ADDR_KEY = 'EE_DAUTH_R1_ADDR'
|
5
6
|
|
6
7
|
EE_GENESIS_EPOCH_DATE_KEY = 'EE_GENESIS_EPOCH_DATE'
|
7
8
|
EE_EPOCH_INTERVALS_KEY = 'EE_EPOCH_INTERVALS'
|
@@ -15,6 +16,7 @@ EVM_NET_DATA = {
|
|
15
16
|
'mainnet': {
|
16
17
|
EvmNetData.DAUTH_URL_KEY : "https://dauth.ratio1.ai/get_auth_data",
|
17
18
|
EvmNetData.DAUTH_ND_ADDR_KEY : "0xE20198EE2B76eED916A568a47cdea9681f7c79BF",
|
19
|
+
EvmNetData.DAUTH_R1_ADDR_KEY : "0xc992DcaB6D3F8783fBf0c935E7bCeB20aa50A6f1",
|
18
20
|
EvmNetData.DAUTH_RPC_KEY : "https://base-mainnet.public.blastapi.io",
|
19
21
|
EvmNetData.EE_GENESIS_EPOCH_DATE_KEY : "2025-02-05 16:00:00",
|
20
22
|
EvmNetData.EE_EPOCH_INTERVALS_KEY : 24,
|
@@ -26,6 +28,7 @@ EVM_NET_DATA = {
|
|
26
28
|
'testnet': {
|
27
29
|
EvmNetData.DAUTH_URL_KEY : "https://testnet-dauth.ratio1.ai/get_auth_data",
|
28
30
|
EvmNetData.DAUTH_ND_ADDR_KEY : "0xE20198EE2B76eED916A568a47cdea9681f7c79BF",
|
31
|
+
EvmNetData.DAUTH_R1_ADDR_KEY : "0xc992DcaB6D3F8783fBf0c935E7bCeB20aa50A6f1",
|
29
32
|
EvmNetData.DAUTH_RPC_KEY : "https://base-sepolia.public.blastapi.io",
|
30
33
|
EvmNetData.EE_GENESIS_EPOCH_DATE_KEY : "2025-02-05 16:00:00",
|
31
34
|
EvmNetData.EE_EPOCH_INTERVALS_KEY : 24,
|
@@ -38,6 +41,7 @@ EVM_NET_DATA = {
|
|
38
41
|
'devnet' : {
|
39
42
|
EvmNetData.DAUTH_URL_KEY : "https://devnet-dauth.ratio1.ai/get_auth_data",
|
40
43
|
EvmNetData.DAUTH_ND_ADDR_KEY : "0x9f49fc29366F1C8285d42e7E82cA0bb668B32CeA",
|
44
|
+
EvmNetData.DAUTH_R1_ADDR_KEY : "0xEF38a3d84D3E3111fb7b794Ba3240187b8B32825",
|
41
45
|
EvmNetData.DAUTH_RPC_KEY : "https://base-sepolia.public.blastapi.io",
|
42
46
|
EvmNetData.EE_GENESIS_EPOCH_DATE_KEY : "2025-02-12 16:00:00",
|
43
47
|
EvmNetData.EE_EPOCH_INTERVALS_KEY : 1,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: naeural_client
|
3
|
-
Version: 3.0
|
3
|
+
Version: 3.1.0
|
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,10 +1,10 @@
|
|
1
1
|
naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
|
2
|
-
naeural_client/_ver.py,sha256=
|
2
|
+
naeural_client/_ver.py,sha256=38HgbYd0O610ADMgWk8TVOk4AsO8FARwG5095hnCzG4,330
|
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
|
6
6
|
naeural_client/base/distributed_custom_code_presets.py,sha256=cvz5R88P6Z5V61Ce1vHVVh8bOkgXd6gve_vdESDNAsg,2544
|
7
|
-
naeural_client/base/generic_session.py,sha256=
|
7
|
+
naeural_client/base/generic_session.py,sha256=eIN-VG1Mr7Z8fqZBngUvS29a0QdAnxT1TIgZxjvXEHE,116714
|
8
8
|
naeural_client/base/instance.py,sha256=bDb9y9ez1vLEGGOCAACQoil7Dw-h7UAwCc18IEfqEas,20789
|
9
9
|
naeural_client/base/pipeline.py,sha256=GYqDd59QQEn7_MTM_dhWsZtdit5q3rECC8HEivWXowo,60068
|
10
10
|
naeural_client/base/plugin_template.py,sha256=7YAFaND2iXoZLgtunjYkFf_TBGieFr3VdNLO3vCqzmM,138795
|
@@ -14,17 +14,17 @@ 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=CNFhPYMj45oVoP0xU9w8VzLUOBHgSljj8pFIzxjUwLg,44568
|
18
18
|
naeural_client/bc/chain.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
naeural_client/bc/ec.py,sha256=FwlkWmJvQ9aHuf_BZX1CWSUAxw6OZ9jBparLIWcs_e4,18933
|
20
|
-
naeural_client/bc/evm.py,sha256=
|
20
|
+
naeural_client/bc/evm.py,sha256=mb1jltZ-KYSQVY75CSXtr8OtXwQyaMGVSl67-UCs620,23869
|
21
21
|
naeural_client/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
22
|
naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
|
23
23
|
naeural_client/certs/s624dbd4.ala.us-east-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
|
24
24
|
naeural_client/cli/README.md,sha256=WPdI_EjzAbUW1aPyj1sSR8rLydcJKZtoiaEtklQrjHo,74
|
25
25
|
naeural_client/cli/cli.py,sha256=MH43FKpUfEG5Y8x8n1KZQh3UaSiLOwyvrWiYp_wLVW4,4070
|
26
26
|
naeural_client/cli/cli_commands.py,sha256=XfZGVCSD2-rUr2EdQXOxxN2VwQd2f2aTMeSgRzXnuvs,3829
|
27
|
-
naeural_client/cli/nodes.py,sha256=
|
27
|
+
naeural_client/cli/nodes.py,sha256=F7_qGplqOnrU2vLqBYFFn3ifgSoWHarHPrx89I6JI9w,5816
|
28
28
|
naeural_client/cli/oracles.py,sha256=Y_PzHshfSERS_Utjjtw5d_BsQRdGr6P4L6uW8yTdA0M,4809
|
29
29
|
naeural_client/code_cheker/__init__.py,sha256=pwkdeZGVL16ZA4Qf2mRahEhoOvKhL7FyuQbMFLr1E5M,33
|
30
30
|
naeural_client/code_cheker/base.py,sha256=lT5DRIFO5rqzsMNCmdMRfkAeevmezozehyfgmhnKpuI,19074
|
@@ -38,7 +38,7 @@ naeural_client/const/apps.py,sha256=ePBiJXLuPfFOKuw-LJrT9OWbaodU7QApfDurIPNDoB4,
|
|
38
38
|
naeural_client/const/base.py,sha256=zfJyGGdrNz_OA5i_6cQxH2lEeJ4PO3092NrwM_gZ_U8,5670
|
39
39
|
naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
|
40
40
|
naeural_client/const/environment.py,sha256=RpdDhDgB8NgRoFTk28eODigf9y0WcT9lul6mBOD029w,879
|
41
|
-
naeural_client/const/evm_net.py,sha256=
|
41
|
+
naeural_client/const/evm_net.py,sha256=ZBlnyuNrcaLzyisckgDE_1bnM2udPo0vmOAesyS98V0,3220
|
42
42
|
naeural_client/const/formatter.py,sha256=AW3bWlqf39uaqV4BBUuW95qKYfF2OkkU4f9hy3kSVhM,200
|
43
43
|
naeural_client/const/heartbeat.py,sha256=xHZBX_NzHTklwA2_AEKR0SGdlbavMT4nirqjQg8WlTU,2550
|
44
44
|
naeural_client/const/misc.py,sha256=VDCwwpf5bl9ltx9rzT2WPVP8B3mZFRufU1tSS5MO240,413
|
@@ -96,8 +96,8 @@ naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_L
|
|
96
96
|
naeural_client/utils/config.py,sha256=upTCJWpZ-Or8V_71DHrIZ429LKn08KNySKcw0WIADcc,10348
|
97
97
|
naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
|
98
98
|
naeural_client/utils/oracle_sync/oracle_tester.py,sha256=X-923ccjkr6_kzbbiuAAcWSIhMtBDOH2VURjTh55apQ,27235
|
99
|
-
naeural_client-3.0.
|
100
|
-
naeural_client-3.0.
|
101
|
-
naeural_client-3.0.
|
102
|
-
naeural_client-3.0.
|
103
|
-
naeural_client-3.0.
|
99
|
+
naeural_client-3.1.0.dist-info/METADATA,sha256=vsuimbxed9PBhcijsT7y795y4TEaztysc2tCnIogIEY,12353
|
100
|
+
naeural_client-3.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
101
|
+
naeural_client-3.1.0.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
|
102
|
+
naeural_client-3.1.0.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
|
103
|
+
naeural_client-3.1.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|