diff --git a/modules/__init__.py b/modules/__init__.py index a06e0aa5..5a44fa3e 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -7,6 +7,7 @@ from modules.single_pool import SingleNominatorModule from modules.validator import ValidatorModule from modules.controller import ControllerModule +from modules.liteserver import LiteserverModule MODES = { @@ -14,6 +15,7 @@ 'nominator-pool': NominatorPoolModule, 'single-nominator': SingleNominatorModule, 'liquid-staking': ControllerModule, + 'liteserver': LiteserverModule } @@ -44,6 +46,7 @@ class Setting: 'overlayTelemetryUrl': Setting(None, 'https://telemetry.toncenter.com/report_overlays', 'Overlay telemetry url'), 'duplicateApi': Setting(None, 'sendTelemetry', 'Duplicate external to Toncenter'), 'duplicateApiUrl': Setting(None, 'https://[testnet.]toncenter.com/api/v2/sendBoc', 'Toncenter api url for duplicate'), + 'checkAdnl': Setting(None, 'sendTelemetry', 'Check local udp port and adnl connection'), 'liteclient_timeout': Setting(None, 3, 'Liteclient default timeout'), 'console_timeout': Setting(None, 3, 'Validator console default timeout'), 'fift_timeout': Setting(None, 3, 'Fift default timeout'), diff --git a/modules/liteserver.py b/modules/liteserver.py new file mode 100644 index 00000000..35acb224 --- /dev/null +++ b/modules/liteserver.py @@ -0,0 +1,12 @@ +import psutil + +from modules.module import MtcModule + + +class LiteserverModule(MtcModule): + + description = 'For liteserver usage only without validator.' + default_value = False + + def add_console_commands(self, console): + ... diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index ad72a94c..c4f263d2 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -78,42 +78,6 @@ def activate_pool(self, args): self.do_activate_pool(pool) color_print("ActivatePool - {green}OK{endc}") - def do_deposit_to_pool(self, pool_addr, amount): - wallet = self.ton.GetValidatorWallet() - bocPath = self.ton.local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" - fiftScript = self.ton.contractsDir + "nominator-pool/func/validator-deposit.fif" - args = [fiftScript, bocPath] - result = self.ton.fift.Run(args) - resultFilePath = self.ton.SignBocWithWallet(wallet, bocPath, pool_addr, amount) - self.ton.SendFile(resultFilePath, wallet) - - def deposit_to_pool(self, args): - try: - poll_addr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") - return - self.do_deposit_to_pool(poll_addr, amount) - color_print("DepositToPool - {green}OK{endc}") - - def do_withdraw_from_pool(self, pool_addr, amount): - pool_data = self.ton.GetPoolData(pool_addr) - if pool_data["state"] == 0: - self.ton.WithdrawFromPoolProcess(pool_addr, amount) - else: - self.ton.PendWithdrawFromPool(pool_addr, amount) - - def withdraw_from_pool(self, args): - try: - pool_addr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") - return - self.do_withdraw_from_pool(pool_addr, amount) - color_print("WithdrawFromPool - {green}OK{endc}") - def update_validator_set(self, args): try: pool_addr = args[0] @@ -127,8 +91,4 @@ def update_validator_set(self, args): def add_console_commands(self, console): console.AddItem("new_pool", self.new_pool, self.local.translate("new_pool_cmd")) console.AddItem("activate_pool", self.activate_pool, self.local.translate("activate_pool_cmd")) - console.AddItem("deposit_to_pool", self.deposit_to_pool, self.local.translate("deposit_to_pool_cmd")) - console.AddItem("withdraw_from_pool", self.withdraw_from_pool, self.local.translate("withdraw_from_pool_cmd")) console.AddItem("update_validator_set", self.update_validator_set, self.local.translate("update_validator_set_cmd")) - - diff --git a/modules/pool.py b/modules/pool.py index 16b481c5..ba37b16c 100644 --- a/modules/pool.py +++ b/modules/pool.py @@ -58,7 +58,45 @@ def check_download_pool_contract_scripts(self): if not os.path.isdir(contract_path): self.ton.DownloadContract("https://github.com/ton-blockchain/nominator-pool") + def do_deposit_to_pool(self, pool_addr, amount): + wallet = self.ton.GetValidatorWallet() + bocPath = self.ton.local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" + fiftScript = self.ton.contractsDir + "nominator-pool/func/validator-deposit.fif" + args = [fiftScript, bocPath] + result = self.ton.fift.Run(args) + resultFilePath = self.ton.SignBocWithWallet(wallet, bocPath, pool_addr, amount) + self.ton.SendFile(resultFilePath, wallet) + + def deposit_to_pool(self, args): + try: + poll_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") + return + self.do_deposit_to_pool(poll_addr, amount) + color_print("DepositToPool - {green}OK{endc}") + + def do_withdraw_from_pool(self, pool_addr, amount): + pool_data = self.ton.GetPoolData(pool_addr) + if pool_data["state"] == 0: + self.ton.WithdrawFromPoolProcess(pool_addr, amount) + else: + self.ton.PendWithdrawFromPool(pool_addr, amount) + + def withdraw_from_pool(self, args): + try: + pool_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") + return + self.do_withdraw_from_pool(pool_addr, amount) + color_print("WithdrawFromPool - {green}OK{endc}") + def add_console_commands(self, console): console.AddItem("pools_list", self.print_pools_list, self.local.translate("pools_list_cmd")) console.AddItem("delete_pool", self.delete_pool, self.local.translate("delete_pool_cmd")) console.AddItem("import_pool", self.import_pool, self.local.translate("import_pool_cmd")) + console.AddItem("deposit_to_pool", self.deposit_to_pool, self.local.translate("deposit_to_pool_cmd")) + console.AddItem("withdraw_from_pool", self.withdraw_from_pool, self.local.translate("withdraw_from_pool_cmd")) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 9e9f4d05..0cca873a 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -10,6 +10,7 @@ import subprocess from mytoncore.mytoncore import MyTonCore +from mytonctrl.utils import fix_git_config from mytoninstaller.config import GetConfig from mypylib.mypylib import ( b2mb, @@ -54,6 +55,8 @@ def Event(local, event_name): ValidatorDownEvent(local) elif event_name == "enable_ton_storage_provider": enable_ton_storage_provider_event(local) + elif event_name == "enable_liteserver_mode": + enable_liteserver_mode(local) local.exit() # end define @@ -90,6 +93,13 @@ def enable_ton_storage_provider_event(local): #end define +def enable_liteserver_mode(local): + ton = MyTonCore(local) + ton.disable_mode('validator') + ton.enable_mode('liteserver') +#end define + + def Elections(local, ton): use_pool = ton.using_pool() use_liquid_staking = ton.using_liquid_staking() @@ -411,7 +421,9 @@ def Telemetry(local, ton): # Get git hashes gitHashes = dict() - gitHashes["mytonctrl"] = get_git_hash("/usr/src/mytonctrl") + mtc_path = "/usr/src/mytonctrl" + local.try_function(fix_git_config, args=[mtc_path]) + gitHashes["mytonctrl"] = get_git_hash(mtc_path) gitHashes["validator"] = GetBinGitHash( "/usr/bin/ton/validator-engine/validator-engine") data["gitHashes"] = gitHashes diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 9cd98d64..f72f26ba 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1208,6 +1208,8 @@ def SignBocWithWallet(self, wallet, boc_path, dest, coins, **kwargs): elif "v3" in wallet.version: fift_script = "wallet-v3.fif" args = [fift_script, wallet.path, dest, subwallet, seqno, coins, boc_mode, boc_path, result_file_path] + else: + raise Exception(f"SignBocWithWallet error: Wallet version '{wallet.version}' is not supported") if flags: args += flags result = self.fift.Run(args) @@ -1912,6 +1914,8 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): elif "v3" in wallet.version: fiftScript = "wallet-v3.fif" args = [fiftScript, wallet.path, dest, subwallet, seqno, coins, "-m", mode, resultFilePath] + else: + raise Exception(f"MoveCoins error: Wallet version '{wallet.version}' is not supported") if flags: args += flags result = self.fift.Run(args) @@ -2276,6 +2280,9 @@ def GetComplaints(self, electionId=None, past=False): complaints[chash] = item #end for + # sort complaints by their creation time and hash + complaints = dict(sorted(complaints.items(), key=lambda item: (item[1]["createdTime"], item[0]))) + # Set buffer self.SetFunctionBuffer(bname, complaints) @@ -2707,6 +2714,43 @@ def GetDbSize(self, exceptions="log"): return result #end define + def check_adnl(self): + telemetry = self.local.db.get("sendTelemetry", False) + check_adnl = self.local.db.get("checkAdnl", telemetry) + if not check_adnl: + return + url = 'http://45.129.96.53/adnl_check' + try: + data = self.get_local_adnl_data() + response = requests.post(url, json=data, timeout=5).json() + except Exception as e: + self.local.add_log(f'Failed to check adnl connection: {type(e)}: {e}', 'error') + return False + result = response.get("ok") + if not result: + self.local.add_log(f'Failed to check adnl connection to local node: {response.get("message")}', 'error') + return result + #end define + + def get_local_adnl_data(self): + + def int2ip(dec): + import socket + return socket.inet_ntoa(struct.pack("!i", dec)) + + vconfig = self.GetValidatorConfig() + + data = {"host": int2ip(vconfig["addrs"][0]["ip"]), "port": vconfig["addrs"][0]["port"]} + + dht_id = vconfig["dht"][0]["id"] + dht_id_hex = base64.b64decode(dht_id).hex().upper() + + result = self.validatorConsole.Run(f"exportpub {dht_id_hex}") + pubkey = parse(result, "got public key: ", "\n") + data["pubkey"] = base64.b64encode(base64.b64decode(pubkey)[4:]).decode() + return data + #end define + def Result2List(self, text): buff = parse(text, "result:", "\n") if buff is None or "error" in buff: @@ -3220,9 +3264,20 @@ def get_modes(self): current_modes[name] = mode.default_value # assign default mode value return current_modes + def check_enable_mode(self, name): + if name == 'liteserver': + if self.using_validator(): + raise Exception(f'Cannot enable liteserver mode while validator mode is enabled. ' + f'Use `disable_mode validator` first.') + if name == 'validator': + if self.using_liteserver(): + raise Exception(f'Cannot enable validator mode while liteserver mode is enabled. ' + f'Use `disable_mode liteserver` first.') + def enable_mode(self, name): if name not in MODES: raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') + self.check_enable_mode(name) current_modes = self.get_modes() current_modes[name] = True self.local.save() @@ -3255,6 +3310,9 @@ def using_pool(self) -> bool: def using_validator(self): return self.get_mode_value('validator') + def using_liteserver(self): + return self.get_mode_value('liteserver') + def Tlb2Json(self, text): # Заменить скобки start = 0 diff --git a/mytonctrl.py b/mytonctrl.py index 6c6eb9d5..4056f883 100644 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -5,6 +5,13 @@ # import os import sys +import subprocess + +requirements_path = "/usr/src/mytonctrl/requirements.txt" +if os.path.isfile(requirements_path): + args = ["pip3", "install", "-r", requirements_path] + subprocess.run(args) +#end if sys.path.insert(0, '/usr/bin/mytonctrl') # Add path to mytonctrl module diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 216ac25f..28d2b16c 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -39,8 +39,9 @@ GetSwapInfo, GetBinGitHash, ) +from mytoncore.telemetry import is_host_virtual from mytonctrl.migrate import run_migrations -from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime +from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime, fix_git_config import sys, getopt, os @@ -141,7 +142,7 @@ def inject_globals(func): module = NominatorPoolModule(ton, local) module.add_console_commands(console) - if ton.get_mode_value('single-nominator'): + if ton.using_single_nominator(): from modules.single_pool import SingleNominatorModule module = SingleNominatorModule(ton, local) module.add_console_commands(console) @@ -186,7 +187,6 @@ def inject_globals(func): #end define - def activate_ton_storage_provider(local, ton, args): wallet_name = "provider_wallet_001" wallet = ton.GetLocalWallet(wallet_name) @@ -238,10 +238,11 @@ def check_installer_user(local): #end define -def PreUp(local, ton): +def PreUp(local: MyPyClass, ton: MyTonCore): CheckMytonctrlUpdate(local) check_installer_user(local) check_vport(local, ton) + ton.check_adnl() warnings(local, ton) # CheckTonUpdate() #end define @@ -249,8 +250,10 @@ def PreUp(local, ton): def Installer(args): # args = ["python3", "/usr/src/mytonctrl/mytoninstaller.py"] - args = ["python3", "-m", "mytoninstaller"] - subprocess.run(args) + cmd = ["python3", "-m", "mytoninstaller"] + if args: + cmd += ["-c", *args] + subprocess.run(cmd) #end define @@ -290,21 +293,6 @@ def check_vport(local, ton): #end define -def fix_git_config(git_path: str): - args = ["git", "status"] - try: - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=git_path, timeout=3) - err = process.stderr.decode("utf-8") - except Exception as e: - err = str(e) - if err: - if 'git config --global --add safe.directory' in err: - args = ["git", "config", "--global", "--add", "safe.directory", git_path] - subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) - else: - raise Exception(f'Failed to check git status: {err}') - - def check_git(input_args, default_repo, text): src_dir = "/usr/src" git_path = f"{src_dir}/{default_repo}" @@ -340,7 +328,7 @@ def check_git(input_args, default_repo, text): need_branch = local_branch check_branch_exists(need_author, need_repo, need_branch) return need_author, need_repo, need_branch - +#end define def check_branch_exists(author, repo, branch): url = f"https://github.com/{author}/{repo}.git" @@ -349,7 +337,7 @@ def check_branch_exists(author, repo, branch): output = process.stdout.decode("utf-8") if branch not in output: raise Exception(f"Branch {branch} not found in {url}") - +#end define def Update(local, args): repo = "mytonctrl" @@ -398,7 +386,7 @@ def Upgrade(ton, args): else: text = "Upgrade - {red}Error{endc}" color_print(text) - +#end define def rollback_to_mtc1(local, ton, args): color_print("{red}Warning: this is dangerous, please make sure you've backed up mytoncore's db.{endc}") @@ -417,7 +405,7 @@ def rollback_to_mtc1(local, ton, args): run_args = ["bash", rollback_script_path] run_as_root(run_args) local.exit() - +#end define def cleanup_validator_db(ton, args): cleanup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/cleanup.sh') @@ -467,8 +455,35 @@ def check_disk_usage(local, ton): print_warning(local, "disk_usage_warning") #end define +def check_sync(local, ton): + validator_status = ton.GetValidatorStatus() + if not validator_status.is_working or validator_status.out_of_sync >= 20: + print_warning(local, "sync_warning") +#end define + +def check_validator_balance(local, ton): + if ton.using_validator(): + validator_wallet = ton.GetValidatorWallet() + validator_account = local.try_function(ton.GetAccount, args=[validator_wallet.addrB64]) + if validator_account is None: + local.add_log(f"Failed to check validator wallet balance", "warning") + return + if validator_account.balance < 100: + print_warning(local, "validator_balance_warning") +#end define + +def check_vps(local, ton): + if ton.using_validator(): + data = local.try_function(is_host_virtual) + if data and data["virtual"]: + color_print(f"Virtualization detected: {data['product_name']}") + def warnings(local, ton): check_disk_usage(local, ton) + check_sync(local, ton) + check_validator_balance(local, ton) + check_vps(local, ton) +#end define def CheckTonUpdate(local): git_path = "/usr/src/ton" @@ -512,64 +527,84 @@ def PrintStatus(local, ton, args): opt = None if len(args) == 1: opt = args[0] - adnlAddr = ton.GetAdnlAddr() - rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() - config34 = ton.GetConfig34() - config36 = ton.GetConfig36() - totalValidators = config34["totalValidators"] + + # Local status + validator_status = ton.GetValidatorStatus() + adnl_addr = ton.GetAdnlAddr() + validator_index = None onlineValidators = None - validatorEfficiency = None - if opt != "fast": - onlineValidators = ton.GetOnlineValidators() - validatorEfficiency = ton.GetValidatorEfficiency() - if onlineValidators: - onlineValidators = len(onlineValidators) - oldStartWorkTime = config36.get("startWorkTime") - if oldStartWorkTime is None: - oldStartWorkTime = config34.get("startWorkTime") - shardsNumber = ton.GetShardsNumber() - validatorStatus = ton.GetValidatorStatus() - config15 = ton.GetConfig15() - config17 = ton.GetConfig17() - fullConfigAddr = ton.GetFullConfigAddr() - fullElectorAddr = ton.GetFullElectorAddr() - startWorkTime = ton.GetActiveElectionId(fullElectorAddr) - validatorIndex = ton.GetValidatorIndex() - validatorWallet = ton.GetValidatorWallet() - dbSize = ton.GetDbSize() - dbUsage = ton.GetDbUsage() - memoryInfo = GetMemoryInfo() - swapInfo = GetSwapInfo() - offersNumber = ton.GetOffersNumber() - complaintsNumber = ton.GetComplaintsNumber() + validator_efficiency = None + validator_wallet = ton.GetValidatorWallet() + validator_account = Dict() + db_size = ton.GetDbSize() + db_usage = ton.GetDbUsage() + memory_info = GetMemoryInfo() + swap_info = GetSwapInfo() statistics = ton.GetSettings("statistics") - tpsAvg = ton.GetStatistics("tpsAvg", statistics) - netLoadAvg = ton.GetStatistics("netLoadAvg", statistics) - disksLoadAvg = ton.GetStatistics("disksLoadAvg", statistics) - disksLoadPercentAvg = ton.GetStatistics("disksLoadPercentAvg", statistics) - if validatorWallet is not None: - validatorAccount = ton.GetAccount(validatorWallet.addrB64) - else: - validatorAccount = None - PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) - PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg) - PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) - PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) + net_load_avg = ton.GetStatistics("netLoadAvg", statistics) + disks_load_avg = ton.GetStatistics("disksLoadAvg", statistics) + disks_load_percent_avg = ton.GetStatistics("disksLoadPercentAvg", statistics) + + all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 + if all_status: + network_name = ton.GetNetworkName() + rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() + config34 = ton.GetConfig34() + config36 = ton.GetConfig36() + totalValidators = config34["totalValidators"] + + if opt != "fast": + onlineValidators = ton.GetOnlineValidators() + validator_efficiency = ton.GetValidatorEfficiency() + if onlineValidators: + onlineValidators = len(onlineValidators) + + oldStartWorkTime = config36.get("startWorkTime") + if oldStartWorkTime is None: + oldStartWorkTime = config34.get("startWorkTime") + shardsNumber = ton.GetShardsNumber() + + config15 = ton.GetConfig15() + config17 = ton.GetConfig17() + fullConfigAddr = ton.GetFullConfigAddr() + fullElectorAddr = ton.GetFullElectorAddr() + startWorkTime = ton.GetActiveElectionId(fullElectorAddr) + validator_index = ton.GetValidatorIndex() + + offersNumber = ton.GetOffersNumber() + complaintsNumber = ton.GetComplaintsNumber() + + tpsAvg = ton.GetStatistics("tpsAvg", statistics) + + if validator_wallet is not None: + validator_account = ton.GetAccount(validator_wallet.addrB64) + #end if + + if all_status: + PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) + PrintLocalStatus(local, adnl_addr, validator_index, validator_efficiency, validator_wallet, validator_account, validator_status, + db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg) + if all_status: + PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) + PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) #end define -def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): - tps1 = tpsAvg[0] - tps5 = tpsAvg[1] - tps15 = tpsAvg[2] +def PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): + #tps1 = tpsAvg[0] + #tps5 = tpsAvg[1] + #tps15 = tpsAvg[2] allValidators = totalValidators newOffers = offersNumber.get("new") allOffers = offersNumber.get("all") newComplaints = complaintsNumber.get("new") allComplaints = complaintsNumber.get("all") - tps1_text = bcolors.green_text(tps1) - tps5_text = bcolors.green_text(tps5) - tps15_text = bcolors.green_text(tps15) - tps_text = local.translate("ton_status_tps").format(tps1_text, tps5_text, tps15_text) + #tps1_text = bcolors.green_text(tps1) + #tps5_text = bcolors.green_text(tps5) + #tps15_text = bcolors.green_text(tps15) + + color_network_name = bcolors.green_text(network_name) if network_name == "mainnet" else bcolors.yellow_text(network_name) + network_name_text = local.translate("ton_status_network_name").format(color_network_name) + #tps_text = local.translate("ton_status_tps").format(tps1_text, tps5_text, tps15_text) onlineValidators_text = GetColorInt(onlineValidators, border=allValidators*2/3, logic="more") allValidators_text = bcolors.yellow_text(allValidators) validators_text = local.translate("ton_status_validators").format(onlineValidators_text, allValidators_text) @@ -588,7 +623,8 @@ def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shar election_text = local.translate("ton_status_election").format(election_text) color_print(local.translate("ton_status_head")) - print(tps_text) + print(network_name_text) + #print(tps_text) print(validators_text) print(shards_text) print(offers_text) @@ -686,6 +722,8 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid validatorBinGitPath = "/usr/bin/ton/validator-engine/validator-engine" mtcGitHash = get_git_hash(mtcGitPath, short=True) validatorGitHash = GetBinGitHash(validatorBinGitPath, short=True) + fix_git_config(mtcGitPath) + fix_git_config(validatorGitPath) mtcGitBranch = get_git_branch(mtcGitPath) validatorGitBranch = get_git_branch(validatorGitPath) mtcGitHash_text = bcolors.yellow_text(mtcGitHash) @@ -1370,7 +1408,7 @@ def enable_mode(local, ton, args): ton.enable_mode(name) color_print("enable_mode - {green}OK{endc}") local.exit() - +#end define def disable_mode(local, ton, args): try: @@ -1381,7 +1419,7 @@ def disable_mode(local, ton, args): ton.disable_mode(name) color_print("disable_mode - {green}OK{endc}") local.exit() - +#end define def Xrestart(inputArgs): if len(inputArgs) < 2: @@ -1435,6 +1473,7 @@ def GetPoolData(ton, args): pool_addr = pool.addrB64 pool_data = ton.GetPoolData(pool_addr) print(json.dumps(pool_data, indent=4)) +#end define ### Start of the program diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 4c41a424..6b3a2823 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -224,6 +224,11 @@ "ru": "{cyan}===[ Статус сети TON ]==={endc}", "zh_TW": "{cyan}===[ TON 網路狀態 ]==={endc}" }, + "ton_status_network_name": { + "en": "Network name: {0}", + "ru": "Название сети: {0}", + "zh_TW": "網路名字: {0}" + }, "ton_status_tps": { "en": "Transactions per second (TPS): {0}, {1}, {2}", "ru": "Транзакций в секунду (TPS): {0}, {1}, {2}", @@ -414,6 +419,26 @@ "ru": "{green}Доступно обновление TON. {red}Пожалуйста, обновите его с помощью команды `upgrade`.{endc}", "zh_TW": "{green}TON 有可用更新. {red}請使用 `upgrade` 命令進行更新.{endc}" }, + "disk_usage_warning": { + "en": "{red} Disk is almost full, clean the TON database immediately: https://docs.ton.org/participate/nodes/node-maintenance-and-security#database-grooming {endc}", + "ru": "{red} Диск почти заполнен, немедленно очистите базу данных TON: https://docs.ton.org/participate/nodes/node-maintenance-and-security#database-grooming {endc}", + "zh_TW": "{red} 磁盤幾乎滿了,立即清理 TON 數據庫: https://docs.ton.org/participate/nodes/node-maintenance-and-security#database-grooming {endc}" + }, + "sync_warning": { + "en": "{red} Node is out of sync. The displayed status is incomplete. {endc}", + "ru": "{red} Нода не синхронизирована с сетью. Отображаемый статус не полный. {endc}", + "zh_TW": "{red} 节点不与网络同步。顯示的狀態不完整。 {endc}" + }, + "validator_balance_warning": { + "en": "{red} Validator wallet balance is low. {endc}", + "ru": "{red} Баланс кошелька валидатора низкий. {endc}", + "zh_TW": "{red} 驗證者錢包餘額不足。 {endc}" + }, + "vps_warning": { + "en": "{red} Validator is running on a VPS. Use a dedicated server for better performance. {endc}", + "ru": "{red} Валидатор работает на VPS. Используйте выделенный сервер (дедик) для лучшей производительности. {endc}", + "zh_TW": "{red} 驗證者在 VPS 上運行。使用專用服務器以獲得更好的性能。 {endc}" + }, "vport_error": { "en": "{red}Error - UDP port of the validator is not accessible from the outside.{endc}", "ru": "{red}Ошибка - UDP порт валидатора недоступен извне.{endc}", diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index c7580ef8..7814f0aa 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -29,7 +29,7 @@ COLOR='\033[92m' ENDC='\033[0m' # Установить дополнительные зависимости -apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio rocksdb-tools liblz4-dev +apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio rocksdb-tools liblz4-dev libjemalloc-dev # bugfix if the files are in the wrong place wget "https://ton-blockchain.github.io/global.config.json" -O global.config.json @@ -76,7 +76,7 @@ rm -rf .ninja_* memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') cpuNumber=$(cat /proc/cpuinfo | grep "processor" | wc -l) -cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a +cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DTON_USE_JEMALLOC=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a ninja -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy systemctl restart validator diff --git a/mytonctrl/utils.py b/mytonctrl/utils.py index 12dba3c9..ba6cd105 100644 --- a/mytonctrl/utils.py +++ b/mytonctrl/utils.py @@ -1,3 +1,4 @@ +import subprocess import time @@ -12,3 +13,19 @@ def GetItemFromList(data, index): return data[index] except: pass + + +def fix_git_config(git_path: str): + args = ["git", "status"] + try: + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=git_path, timeout=3) + err = process.stderr.decode("utf-8") + except Exception as e: + err = str(e) + if err: + if 'git config --global --add safe.directory' in err: + args = ["git", "config", "--global", "--add", "safe.directory", git_path] + subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + else: + raise Exception(f'Failed to check git status: {err}') +#end define diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 56daf47e..160b9210 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -29,7 +29,8 @@ CreateSymlinks, enable_ls_proxy, enable_ton_storage, - enable_ton_storage_provider + enable_ton_storage_provider, + EnableMode ) from mytoninstaller.config import ( CreateLocalConfig, @@ -237,12 +238,29 @@ def Event(local, name): #end define -def General(local): +def Command(local, args, console): + cmd = args[0] + args = args[1:] + for item in console.menu_items: + if cmd == item.cmd: + console._try(item.func, args) + print() + local.exit() + print(console.unknown_cmd) + local.exit() +#end define + + +def General(local, console): if "-u" in sys.argv: ux = sys.argv.index("-u") user = sys.argv[ux+1] local.buffer.user = user Refresh(local) + if "-c" in sys.argv: + cx = sys.argv.index("-c") + args = sys.argv[cx+1:] + Command(local, args, console) if "-e" in sys.argv: ex = sys.argv.index("-e") name = sys.argv[ex+1] @@ -255,6 +273,10 @@ def General(local): mx = sys.argv.index("--dump") dump = sys.argv[mx+1] local.buffer.dump = str2bool(dump) + if "-m" in sys.argv: + mx = sys.argv.index("-m") + mode = sys.argv[mx+1] + local.buffer.mode = mode #end if FirstMytoncoreSettings(local) @@ -264,6 +286,7 @@ def General(local): BackupVconfig(local) BackupMconfig(local) CreateSymlinks(local) + EnableMode(local) #end define @@ -276,7 +299,7 @@ def mytoninstaller(): Init(local, console) if len(sys.argv) > 1: - General(local) + General(local, console) else: console.Run() local.exit() diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 941e16cc..9f4ca19f 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -34,6 +34,7 @@ def FirstNodeSettings(local): validatorAppPath = local.buffer.validator_app_path globalConfigPath = local.buffer.global_config_path vconfig_path = local.buffer.vconfig_path + archive_ttl = 2592000 if local.buffer.mode == 'liteserver' else 86400 # Проверить конфигурацию if os.path.isfile(vconfig_path): @@ -57,8 +58,7 @@ def FirstNodeSettings(local): # Прописать автозагрузку cpus = psutil.cpu_count() - 1 - cmd = "{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --verbosity 1" - cmd = cmd.format(validatorAppPath=validatorAppPath, globalConfigPath=globalConfigPath, ton_db_dir=ton_db_dir, tonLogPath=tonLogPath, cpus=cpus) + cmd = f"{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --archive-ttl {archive_ttl} --verbosity 1" add2systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" # Получить внешний ip адрес @@ -888,3 +888,13 @@ def CreateSymlinks(local): file.write(fiftpath + '\n') file.close() #end define + + +def EnableMode(local): + args = ["python3", "-m", "mytoncore", "-e"] + if local.buffer.mode == 'liteserver': + args.append("enable_liteserver_mode") + else: + return + args = ["su", "-l", local.buffer.user, "-c", ' '.join(args)] + subprocess.run(args) diff --git a/scripts/install.sh b/scripts/install.sh index b57b9453..cfe84c76 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -15,16 +15,18 @@ fi author="ton-blockchain" repo="mytonctrl" branch="master" +mode="validator" show_help_and_exit() { - echo 'Supported argumets:' - echo ' -c PATH Provide custom config for toninstaller.sh' - echo ' -t Disable telemetry' - echo ' -i Ignore minimum reqiurements' - echo ' -d Use pre-packaged dump. Reduces duration of initial synchronization.' - echo ' -a Set MyTonCtrl git repo author' + echo 'Supported argumets:' + echo ' -c PATH Provide custom config for toninstaller.sh' + echo ' -t Disable telemetry' + echo ' -i Ignore minimum reqiurements' + echo ' -d Use pre-packaged dump. Reduces duration of initial synchronization.' + echo ' -a Set MyTonCtrl git repo author' echo ' -r Set MyTonCtrl git repo' echo ' -b Set MyTonCtrl git repo branch' + echo ' -m MODE Install MyTonCtrl with specified mode (validator or liteserver)' echo ' -h Show this help' exit } @@ -40,7 +42,8 @@ ignore=false dump=false -while getopts c:tida:r:b: flag + +while getopts c:tida:r:b:m: flag do case "${flag}" in c) config=${OPTARG};; @@ -50,6 +53,7 @@ do a) author=${OPTARG};; r) repo=${OPTARG};; b) branch=${OPTARG};; + m) mode=${OPTARG};; h) show_help_and_exit;; *) echo "Flag -${flag} is not recognized. Aborting" @@ -115,7 +119,7 @@ if [ "$parent_name" = "sudo" ] || [ "$parent_name" = "su" ]; then user=$(logname) fi echo "User: $user" -python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} +python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} -m ${mode} # set migrate version migrate_version=1 diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 81feecbd..500a92f3 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -50,7 +50,7 @@ if [ "$OSTYPE" == "linux-gnu" ]; then elif [ -f /etc/debian_version ]; then echo "Ubuntu/Debian Linux detected." apt-get update - apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev liblz4-dev + apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev liblz4-dev libjemalloc-dev # Install ninja apt-get install -y ninja-build @@ -131,7 +131,7 @@ if [[ "$OSTYPE" =~ darwin.* ]]; then cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton fi else - cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a + cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja -DTON_USE_JEMALLOC=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a fi # Расчитываем количество процессоров для сборки