Skip to content

Commit d2b9f98

Browse files
authored
Merge pull request #6 from yungwine/mytonctrl2_dev
merge mtc2dev to modes
2 parents e79e687 + d6a53b0 commit d2b9f98

File tree

16 files changed

+864
-81
lines changed

16 files changed

+864
-81
lines changed

docs/ru/ton-storage-provider.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# TON storage provider
2+
3+
MyTonCtrl поддерживает установку дополнительных компонентов таких как `TON storage` и `TON storage provider`. С их помощью вы можете хранить пользовательские файлы у себя на сервере и получать за это вознаграждение.
4+
5+
## Установка дополнительных компонентов
6+
7+
Войдите в MyTonCtrl
8+
```
9+
mytonctrl
10+
```
11+
12+
Затем войдите в режим установщика
13+
```
14+
installer
15+
```
16+
17+
После включите нужный функционал TON storage provider:
18+
```
19+
enable TSP
20+
```
21+
22+
## Активация контракта провайдера
23+
24+
В ходе установки дополнительных компонетов был создан специальный кошелек провайдера `provider_wallet_001` откуда будут отправляться доказательства и куда будет приходить награда.
25+
Для его работы сначала нужно пополнить этот кошелек на 1 монету и активировать его командой внутри MyTonCtrl, в ходе которого он так же зарегистрируется в списке провайдеров:
26+
```
27+
activate_ton_storage_provider
28+
```
29+
30+
## Панель управления TON storage provider
31+
32+
TODO

modules/custom_overlays.py

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
import json
2+
import requests
3+
4+
from mypylib.mypylib import color_print
5+
from modules.module import MtcModule
6+
from mytoncore.utils import hex2base64
7+
8+
9+
class CustomOverlayModule(MtcModule):
10+
11+
@staticmethod
12+
def parse_config(name: str, config: dict, vset: list = None):
13+
"""
14+
Converts config to validator-console friendly format
15+
:param name: custom overlay name
16+
:param config: config
17+
:param vset: list of validators adnl addresses, can be None if `@validators` not in config
18+
:return:
19+
"""
20+
result = {
21+
"name": name,
22+
"nodes": []
23+
}
24+
for k, v in config.items():
25+
if k == '@validators' and v:
26+
if vset is None:
27+
raise Exception("Validators set is not defined but @validators is in config")
28+
for v_adnl in vset:
29+
result["nodes"].append({
30+
"adnl_id": hex2base64(v_adnl),
31+
"msg_sender": False,
32+
})
33+
else:
34+
result["nodes"].append({
35+
"adnl_id": hex2base64(k),
36+
"msg_sender": v["msg_sender"],
37+
})
38+
if v["msg_sender"]:
39+
result["nodes"][-1]["msg_sender_priority"] = v["msg_sender_priority"]
40+
return result
41+
42+
def add_custom_overlay(self, args):
43+
if len(args) != 2:
44+
color_print("{red}Bad args. Usage:{endc} add_custom_overlay <name> <path_to_config>")
45+
return
46+
path = args[1]
47+
with open(path, 'r') as f:
48+
config = json.load(f)
49+
self.ton.set_custom_overlay(args[0], config)
50+
if '@validators' in config:
51+
print('Dynamic overlay will be added within 1 minute')
52+
else:
53+
result = self.add_custom_overlay_to_vc(self.parse_config(args[0], config))
54+
if not result:
55+
print('Failed to add overlay to validator console')
56+
color_print("add_custom_overlay - {red}ERROR{endc}")
57+
return
58+
color_print("add_custom_overlay - {green}OK{endc}")
59+
60+
def list_custom_overlays(self, args):
61+
if not self.ton.get_custom_overlays():
62+
color_print("{red}No custom overlays{endc}")
63+
return
64+
for k, v in self.ton.get_custom_overlays().items():
65+
color_print(f"Custom overlay {{bold}}{k}{{endc}}:")
66+
print(json.dumps(v, indent=4))
67+
68+
def delete_custom_overlay(self, args):
69+
if len(args) != 1:
70+
color_print("{red}Bad args. Usage:{endc} delete_custom_overlay <name>")
71+
return
72+
if '@validators' in self.ton.get_custom_overlays().get(args[0], {}):
73+
self.ton.delete_custom_overlay(args[0])
74+
print('Dynamic overlay will be deleted within 1 minute')
75+
else:
76+
self.ton.delete_custom_overlay(args[0])
77+
result = self.delete_custom_overlay_from_vc(args[0])
78+
if not result:
79+
print('Failed to delete overlay from validator console')
80+
color_print("delete_custom_overlay - {red}ERROR{endc}")
81+
return
82+
color_print("delete_custom_overlay - {green}OK{endc}")
83+
84+
def check_node_eligible_for_custom_overlay(self, config: dict):
85+
vconfig = self.ton.GetValidatorConfig()
86+
my_adnls = vconfig.adnl
87+
node_adnls = [i["adnl_id"] for i in config["nodes"]]
88+
for adnl in my_adnls:
89+
if adnl.id in node_adnls:
90+
return True
91+
return False
92+
93+
def delete_custom_overlay_from_vc(self, name: str):
94+
result = self.ton.validatorConsole.Run(f"delcustomoverlay {name}")
95+
return 'success' in result
96+
97+
def add_custom_overlay_to_vc(self, config: dict):
98+
if not self.check_node_eligible_for_custom_overlay(config):
99+
self.ton.local.add_log(f"Node has no adnl address required for custom overlay {config.get('name')}", "debug")
100+
return False
101+
self.ton.local.add_log(f"Adding custom overlay {config.get('name')}", "debug")
102+
path = self.ton.tempDir + f'/custom_overlay_{config["name"]}.json'
103+
with open(path, 'w') as f:
104+
json.dump(config, f)
105+
result = self.ton.validatorConsole.Run(f"addcustomoverlay {path}")
106+
return 'success' in result
107+
108+
def custom_overlays(self):
109+
config = self.get_default_custom_overlay()
110+
if config is not None:
111+
self.ton.set_custom_overlay('default', config)
112+
self.deploy_custom_overlays()
113+
114+
def deploy_custom_overlays(self):
115+
result = self.ton.validatorConsole.Run("showcustomoverlays")
116+
if 'unknown command' in result:
117+
return # node old version
118+
names = []
119+
for line in result.split('\n'):
120+
if line.startswith('Overlay'):
121+
names.append(line.split(' ')[1].replace('"', '').replace(':', ''))
122+
123+
config34 = self.ton.GetConfig34()
124+
current_el_id = config34['startWorkTime']
125+
current_vset = [i["adnlAddr"] for i in config34['validators']]
126+
127+
config36 = self.ton.GetConfig36()
128+
next_el_id = config36['startWorkTime'] if config36['validators'] else 0
129+
next_vset = [i["adnlAddr"] for i in config36['validators']]
130+
131+
for name in names:
132+
# check that overlay still exists in mtc db
133+
pure_name = name
134+
suffix = name.split('_')[-1]
135+
if suffix.startswith('elid') and suffix.split('elid')[-1].isdigit(): # probably election id
136+
pure_name = '_'.join(name.split('_')[:-1])
137+
el_id = int(suffix.split('elid')[-1])
138+
if el_id not in (current_el_id, next_el_id):
139+
self.ton.local.add_log(f"Overlay {name} is not in current or next election, deleting", "debug")
140+
self.delete_custom_overlay_from_vc(name) # delete overlay if election id is not in current or next election
141+
continue
142+
143+
if pure_name not in self.ton.get_custom_overlays():
144+
self.ton.local.add_log(f"Overlay {name} ({pure_name}) is not in mtc db, deleting", "debug")
145+
self.delete_custom_overlay_from_vc(name) # delete overlay if it's not in mtc db
146+
147+
for name, config in self.ton.get_custom_overlays().items():
148+
if name in names:
149+
continue
150+
if '@validators' in config:
151+
new_name = name + '_elid' + str(current_el_id)
152+
if new_name not in names:
153+
node_config = self.parse_config(new_name, config, current_vset)
154+
self.add_custom_overlay_to_vc(node_config)
155+
156+
if next_el_id != 0:
157+
new_name = name + '_elid' + str(next_el_id)
158+
if new_name not in names:
159+
node_config = self.parse_config(new_name, config, next_vset)
160+
self.add_custom_overlay_to_vc(node_config)
161+
else:
162+
node_config = self.parse_config(name, config)
163+
self.add_custom_overlay_to_vc(node_config)
164+
165+
def get_default_custom_overlay(self):
166+
if not self.ton.local.db.get('useDefaultCustomOverlays', True):
167+
return None
168+
network = self.ton.GetNetworkName()
169+
default_url = 'https://ton-blockchain.github.io/fallback_custom_overlays.json'
170+
url = self.ton.local.db.get('defaultCustomOverlaysUrl', default_url)
171+
resp = requests.get(url)
172+
if resp.status_code != 200:
173+
self.ton.local.add_log(f"Failed to get default custom overlays from {url}", "error")
174+
return None
175+
config = resp.json()
176+
return config.get(network)
177+
178+
def add_console_commands(self, console):
179+
console.AddItem("add_custom_overlay", self.add_custom_overlay, self.local.translate("add_custom_overlay_cmd"))
180+
console.AddItem("list_custom_overlays", self.list_custom_overlays, self.local.translate("list_custom_overlays_cmd"))
181+
console.AddItem("delete_custom_overlay", self.delete_custom_overlay, self.local.translate("delete_custom_overlay_cmd"))

mytoncore/functions.py

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
import psutil
66
import time
77
import json
8+
import base64
89
import requests
910
import subprocess
1011

1112
from mytoncore.mytoncore import MyTonCore
1213
from mytoncore.utils import parse_db_stats
14+
from mytoninstaller.config import GetConfig
1315
from mypylib.mypylib import (
1416
b2mb,
1517
get_timestamp,
@@ -20,14 +22,15 @@
2022
thr_sleep,
2123
Dict
2224
)
25+
from mytoninstaller.node_args import get_node_args
2326

2427

2528
def Init(local):
2629
# Event reaction
2730
if ("-e" in sys.argv):
2831
x = sys.argv.index("-e")
29-
eventName = sys.argv[x+1]
30-
Event(local, eventName)
32+
event_name = sys.argv[x+1]
33+
Event(local, event_name)
3134
# end if
3235

3336
local.run()
@@ -46,11 +49,13 @@ def Init(local):
4649
# end define
4750

4851

49-
def Event(local, eventName):
50-
if eventName == "enableVC":
52+
def Event(local, event_name):
53+
if event_name == "enableVC":
5154
EnableVcEvent(local)
52-
elif eventName == "validator down":
55+
elif event_name == "validator down":
5356
ValidatorDownEvent(local)
57+
elif event_name == "enable_ton_storage_provider":
58+
enable_ton_storage_provider_event(local)
5459
local.exit()
5560
# end define
5661

@@ -78,6 +83,15 @@ def ValidatorDownEvent(local):
7883
# end define
7984

8085

86+
def enable_ton_storage_provider_event(local):
87+
config_path = local.db.ton_storage.provider.config_path
88+
config = GetConfig(path=config_path)
89+
key_bytes = base64.b64decode(config.ProviderKey)
90+
ton = MyTonCore(local)
91+
ton.import_wallet_with_version(key_bytes[:32], version="v3r2", wallet_name="provider_wallet_001")
92+
#end define
93+
94+
8195
def Elections(local, ton):
8296
use_pool = ton.using_pool()
8397
use_liquid_staking = ton.using_liquid_staking()
@@ -460,6 +474,49 @@ def get_db_stats():
460474
# end define
461475

462476

477+
def get_cpu_name():
478+
with open('/proc/cpuinfo') as f:
479+
for line in f:
480+
if line.strip():
481+
if line.rstrip('\n').startswith('model name'):
482+
return line.rstrip('\n').split(':')[1].strip()
483+
return None
484+
485+
486+
def is_host_virtual():
487+
try:
488+
with open('/sys/class/dmi/id/product_name') as f:
489+
product_name = f.read().strip().lower()
490+
if 'virtual' in product_name or 'kvm' in product_name or 'qemu' in product_name or 'vmware' in product_name:
491+
return {'virtual': True, 'product_name': product_name}
492+
return {'virtual': False, 'product_name': product_name}
493+
except FileNotFoundError:
494+
return {'virtual': None, 'product_name': None}
495+
496+
497+
def do_beacon_ping(host, count, timeout):
498+
args = ['ping', '-c', str(count), '-W', str(timeout), host]
499+
process = subprocess.run(args, stdin=subprocess.PIPE,
500+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout)
501+
output = process.stdout.decode("utf-8")
502+
avg = output.split('\n')[-2].split('=')[1].split('/')[1]
503+
return float(avg)
504+
505+
506+
def get_pings_values():
507+
return {
508+
'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 5, 10),
509+
'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 5, 10)
510+
}
511+
512+
513+
def get_validator_disk_name():
514+
process = subprocess.run("df -h /var/ton-work/ | sed -n '2 p' | awk '{print $1}'", stdin=subprocess.PIPE,
515+
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3, shell=True)
516+
output = process.stdout.decode("utf-8")
517+
return output.strip()
518+
519+
463520
def Telemetry(local, ton):
464521
sendTelemetry = local.db.get("sendTelemetry")
465522
if sendTelemetry is not True:
@@ -484,6 +541,10 @@ def Telemetry(local, ton):
484541
data["uname"] = GetUname()
485542
data["vprocess"] = GetValidatorProcessInfo()
486543
data["dbStats"] = get_db_stats()
544+
data["nodeArgs"] = get_node_args()
545+
data["cpuInfo"] = {'cpuName': get_cpu_name(), 'virtual': is_host_virtual()}
546+
data["validatorDiskName"] = get_validator_disk_name()
547+
data["pings"] = get_pings_values()
487548
elections = local.try_function(ton.GetElectionEntries)
488549
complaints = local.try_function(ton.GetComplaints)
489550

@@ -629,6 +690,10 @@ def General(local):
629690
local.start_cycle(Telemetry, sec=60, args=(local, ton, ))
630691
local.start_cycle(OverlayTelemetry, sec=7200, args=(local, ton, ))
631692
local.start_cycle(ScanLiteServers, sec=60, args=(local, ton,))
693+
694+
from modules.custom_overlays import CustomOverlayModule
695+
local.start_cycle(CustomOverlayModule(ton, local).custom_overlays, sec=60, args=())
696+
632697
thr_sleep()
633698
# end define
634699

0 commit comments

Comments
 (0)