diff --git a/.gitignore b/.gitignore index 7f752b37..4123b044 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,124 @@ +# Created by .ignore support plugin (hsz.mobi) +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +#PyCharm +.idea/ +.idea/$CACHE_FILE$ +.idea/.gitignore +.idea/encodings.xml +.idea/inspectionProfiles/ +.idea/misc.xml +.idea/modules.xml +.idea/ton_client.iml +.idea/vcs.xml + *.DS_Store .idea/ __pycache__/ test.py +.vscode/ +venv/ +venv38/ +sandbox/ diff --git a/.gitmodules b/.gitmodules index e6ac5652..fdb48b48 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "mypylib"] path = mypylib - url = https://github.com/igroman787/mypylib.git + url = https://github.com/igroman787/mypylib [submodule "mypyconsole"] path = mypyconsole - url = https://github.com/igroman787/mypyconsole.git + url = https://github.com/igroman787/mypyconsole diff --git a/README.Ru.md b/README.RU.md similarity index 100% rename from README.Ru.md rename to README.RU.md diff --git a/README.md b/README.md index a41b61d4..aaf1d762 100644 --- a/README.md +++ b/README.md @@ -155,4 +155,4 @@ Ready. A local copy of toncenter is available at `http://:800 git: https://github.com/igroman787/pytonv3 # Useful links -* https://docs.ton.org/ \ No newline at end of file +* https://docs.ton.org/ diff --git a/docs/en/FAQ.md b/docs/en/FAQ.md index d016e3a8..a0863b53 100644 --- a/docs/en/FAQ.md +++ b/docs/en/FAQ.md @@ -121,4 +121,4 @@ If you need to restart your validator, you can do so by running the following co systemctl restart validator ``` -Ensure you have sufficient permissions to execute these commands and make necessary adjustments. Always remember to back up important data before performing operations that could potentially affect your validator. \ No newline at end of file +Ensure you have sufficient permissions to execute these commands and make necessary adjustments. Always remember to back up important data before performing operations that could potentially affect your validator. diff --git a/docs/en/import-wallets.md b/docs/en/import-wallets.md index 508f2655..0fcac1c9 100644 --- a/docs/en/import-wallets.md +++ b/docs/en/import-wallets.md @@ -5,11 +5,9 @@ MyTonCtrl supports various types of wallet-like contracts, including wallet-v1, ## Importing Using a Private Key If you have access to a private key, you can easily import a wallet. Enter the following command into the console: - ``` iw ``` - Here, `` is your private key in base64 format. ## Importing Using a Mnemonic Phrase @@ -32,5 +30,4 @@ If you have a mnemonic phrase (a sequence of 24 words like `tattoo during ...`), 6. Open the mytonctrl console and list the wallets using the `wl` command. 7. Verify that the wallet has been imported and displays the correct balance. 8. You can now send funds using the `mg` command. Enter `mg` to view the help documentation. - -Remember to replace placeholders (words inside `< >`) with your actual values when running commands. \ No newline at end of file +Remember to replace placeholders (words inside `< >`) with your actual values when running commands. diff --git a/docs/en/nominator-pool.md b/docs/en/nominator-pool.md index fd80ee6d..4539f2bd 100644 --- a/docs/en/nominator-pool.md +++ b/docs/en/nominator-pool.md @@ -115,4 +115,4 @@ If you're creating a pool for numerous nominators, you might use something like 2. Await the return of both your stakes from the elector. -3. Proceed with the steps under "Running the Validator in Nominator Pool Mode" from the **4th step** onwards. \ No newline at end of file +3. Proceed with the steps under "Running the Validator in Nominator Pool Mode" from the **4th step** onwards. diff --git a/docs/ru/FAQ.md b/docs/ru/FAQ.md index e1436e1d..ddf57bec 100644 --- a/docs/ru/FAQ.md +++ b/docs/ru/FAQ.md @@ -119,4 +119,4 @@ Error: expected str, bytes or os.PathLike object, not NoneType systemctl restart validator ``` -Убедитесь, что у вас есть достаточные права для выполнения этих команд и сделайте необходимые корректировки. Всегда помните о резервном копировании важных данных перед выполнением операций, которые могут потенциально повлиять на ваш валидатор. \ No newline at end of file +Убедитесь, что у вас есть достаточные права для выполнения этих команд и сделайте необходимые корректировки. Всегда помните о резервном копировании важных данных перед выполнением операций, которые могут потенциально повлиять на ваш валидатор. diff --git a/docs/ru/import-wallets.md b/docs/ru/import-wallets.md index 700b7ec9..f61feab9 100644 --- a/docs/ru/import-wallets.md +++ b/docs/ru/import-wallets.md @@ -27,10 +27,10 @@ iw <адрес-кошелька> <секретный-ключ-кошелька> ``` node index.js word1 word2 ... word24 [address] ``` -4. Скрипт сгенерирует `wallet.pk` и `wallet.addr`. Переименуйте их в `imported_wallet.pk` и `imported_wallet.addr`. +4. Скрипт сгенерирует `wallet.pk` и `wallet.addr`. Переименуйте их в `imported_wallet.pk` и `imported_wallet.addr`. 5. Скопируйте оба файла в каталог `~/.local/share/mytoncore/wallets/`. 6. Откройте консоль mytonctrl и перечислите кошельки с помощью команды `wl`. 7. Убедитесь, что кошелек был импортирован и отображает правильный баланс. 8. Теперь вы можете отправить средства с помощью команды `mg`. Введите `mg`, чтобы просмотреть справочную документацию. -Помните, что при выполнении команд следует заменить заполнители (слова внутри `< >`) на ваши фактические значения. \ No newline at end of file +Помните, что при выполнении команд следует заменить заполнители (слова внутри `< >`) на ваши фактические значения. diff --git a/docs/ru/nominator-pool.md b/docs/ru/nominator-pool.md index a735f1b8..7d87b2b1 100644 --- a/docs/ru/nominator-pool.md +++ b/docs/ru/nominator-pool.md @@ -115,4 +115,4 @@ 2. Дождитесь, когда оба ваших депозита вернутся от электора. -3. Следуйте инструкциям "Запуск валидатора в режиме номинантского пула", начиная с **4-го шага**. \ No newline at end of file +3. Следуйте инструкциям "Запуск валидатора в режиме номинантского пула", начиная с **4-го шага**. diff --git a/docs/zh_TW/FAQ.md b/docs/zh_TW/FAQ.md index 54bfce6e..067902ed 100644 --- a/docs/zh_TW/FAQ.md +++ b/docs/zh_TW/FAQ.md @@ -118,4 +118,4 @@ Error: expected str, bytes or os.PathLike object, not NoneType systemctl restart validator ``` -請確保你具有執行這些命令的適當權限,並進行必要的調整。在執行可能影響你的驗證者的操作之前,請始終記得備份重要數據。 \ No newline at end of file +請確保你具有執行這些命令的適當權限,並進行必要的調整。在執行可能影響你的驗證者的操作之前,請始終記得備份重要數據。 diff --git a/docs/zh_TW/import-wallets.md b/docs/zh_TW/import-wallets.md index 8564ed68..1e199e1c 100644 --- a/docs/zh_TW/import-wallets.md +++ b/docs/zh_TW/import-wallets.md @@ -33,4 +33,4 @@ iw 7. 確認錢包已經匯入並且餘額正確。 8. 現在你可以使用 `mg` 命令發送金錢(輸入 `mg` 可查看使用說明)。 -在執行命令時,記得將尖括號內的佔位符(例如 ``、``)替換為實際的值。 \ No newline at end of file +在執行命令時,記得將尖括號內的佔位符(例如 ``、``)替換為實際的值。 diff --git a/docs/zh_TW/manual-ubuntu.md b/docs/zh_TW/manual-ubuntu.md index 4ab6da0a..aa6a98b7 100644 --- a/docs/zh_TW/manual-ubuntu.md +++ b/docs/zh_TW/manual-ubuntu.md @@ -64,4 +64,4 @@ 要檢查 **mytoncrl** 日誌,對於本地用戶,打開 `~/.local/share/mytoncore/mytoncore.log`,對於 Root,打開 `/usr/local/bin/mytoncore/mytoncore.log`。 -![logs](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytoncore-log.png) \ No newline at end of file +![logs](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytoncore-log.png) diff --git a/docs/zh_TW/nominator-pool.md b/docs/zh_TW/nominator-pool.md index e3fac6fe..fd107ca6 100644 --- a/docs/zh_TW/nominator-pool.md +++ b/docs/zh_TW/nominator-pool.md @@ -114,4 +114,4 @@ 2. 等待你的兩個賭注從選民那裡返回。 -3. 從**第四步**開始,按照"在提名人池模式下運行驗證者"的步驟進行操作。 \ No newline at end of file +3. 從**第四步**開始,按照"在提名人池模式下運行驗證者"的步驟進行操作。 diff --git a/mytoncore/__init__.py b/mytoncore/__init__.py new file mode 100644 index 00000000..a39eb41f --- /dev/null +++ b/mytoncore/__init__.py @@ -0,0 +1,4 @@ +from .utils import * +from .mytoncore import * +from mypylib.mypylib import MyPyClass +from mypyconsole.mypyconsole import MyPyConsole diff --git a/mytoncore/__main__.py b/mytoncore/__main__.py new file mode 100644 index 00000000..d905da8f --- /dev/null +++ b/mytoncore/__main__.py @@ -0,0 +1,5 @@ +from mytoncore.functions import mytoncore + + +if __name__ == '__main__': + mytoncore() diff --git a/mytoncore/fift.py b/mytoncore/fift.py new file mode 100644 index 00000000..291b3707 --- /dev/null +++ b/mytoncore/fift.py @@ -0,0 +1,27 @@ +import subprocess + + +class Fift: + def __init__(self, local): + self.local = local + self.appPath = None + self.libsPath = None + self.smartcontsPath = None + #end define + + def Run(self, args, **kwargs): + fift_timeout = self.local.db.fift_timeout if self.local.db.fift_timeout else 3 + timeout = kwargs.get("timeout", fift_timeout) + for i in range(len(args)): + args[i] = str(args[i]) + includePath = self.libsPath + ':' + self.smartcontsPath + args = [self.appPath, "-I", includePath, "-s"] + args + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + output = process.stdout.decode("utf-8") + err = process.stderr.decode("utf-8") + if len(err) > 0: + self.local.add_log("args: {args}".format(args=args), "error") + raise Exception("Fift error: {err}".format(err=err)) + return output + #end define +#end class diff --git a/mytoncore/functions.py b/mytoncore/functions.py new file mode 100755 index 00000000..ac40b572 --- /dev/null +++ b/mytoncore/functions.py @@ -0,0 +1,585 @@ +#!/usr/bin/env python3 +# -*- coding: utf_8 -*-l +import os +import sys +import psutil +import time +import json +import requests +import subprocess + +from mytoncore.mytoncore import MyTonCore, Dec2HexAddr +from mytoncore.tonblocksscanner import TonBlocksScanner +from mypylib.mypylib import ( + b2mb, + get_timestamp, + get_internet_interface_name, + get_service_pid, + get_load_avg, + thr_sleep, + Dict +) + + +def Init(local): + # Event reaction + if ("-e" in sys.argv): + x = sys.argv.index("-e") + eventName = sys.argv[x+1] + Event(local, eventName) + # end if + + local.run() + + # statistics + local.buffer.blocksData = dict() + local.buffer.transData = dict() + local.buffer.network = [None]*15*6 + local.buffer.diskio = [None]*15*6 + + # scan blocks + local.buffer.masterBlocksList = list() + local.buffer.prevShardsBlock = dict() + local.buffer.blocksNum = 0 + local.buffer.transNum = 0 +# end define + + +def Event(local, eventName): + if eventName == "enableVC": + EnableVcEvent(local) + elif eventName == "validator down": + ValidatorDownEvent(local) + local.exit() +# end define + + +def EnableVcEvent(local): + local.add_log("start EnableVcEvent function", "debug") + # Создать новый кошелек для валидатора + ton = MyTonCore(local) + wallet = ton.CreateWallet("validator_wallet_001", -1) + local.db["validatorWalletName"] = wallet.name + + # Создать новый ADNL адрес для валидатора + adnlAddr = ton.CreateNewKey() + ton.AddAdnlAddrToValidator(adnlAddr) + local.db["adnlAddr"] = adnlAddr + + # Сохранить + local.save() +# end define + + +def ValidatorDownEvent(local): + local.add_log("start ValidatorDownEvent function", "debug") + local.add_log("Validator is down", "error") +# end define + + +def Elections(local, ton): + usePool = local.db.get("usePool") + if usePool == True: + ton.PoolsUpdateValidatorSet() + ton.RecoverStake() + ton.ElectionEntry() + else: + ton.RecoverStake() + ton.ElectionEntry() +# end define + + +def Statistics(local): + ReadNetworkData(local) + SaveNetworkStatistics(local) + # ReadTransData(local, scanner) + SaveTransStatistics(local) + ReadDiskData(local) + SaveDiskStatistics(local) +# end define + + +def ReadDiskData(local): + timestamp = get_timestamp() + disks = GetDisksList() + buff = psutil.disk_io_counters(perdisk=True) + data = dict() + for name in disks: + data[name] = dict() + data[name]["timestamp"] = timestamp + data[name]["busyTime"] = buff[name].busy_time + data[name]["readBytes"] = buff[name].read_bytes + data[name]["writeBytes"] = buff[name].write_bytes + data[name]["readCount"] = buff[name].read_count + data[name]["writeCount"] = buff[name].write_count + # end for + + local.buffer.diskio.pop(0) + local.buffer.diskio.append(data) +# end define + + +def SaveDiskStatistics(local): + data = local.buffer.diskio + data = data[::-1] + zerodata = data[0] + buff1 = data[1*6-1] + buff5 = data[5*6-1] + buff15 = data[15*6-1] + if buff5 is None: + buff5 = buff1 + if buff15 is None: + buff15 = buff5 + # end if + + disksLoadAvg = dict() + disksLoadPercentAvg = dict() + iopsAvg = dict() + disks = GetDisksList() + for name in disks: + if zerodata[name]["busyTime"] == 0: + continue + diskLoad1, diskLoadPercent1, iops1 = CalculateDiskStatistics( + zerodata, buff1, name) + diskLoad5, diskLoadPercent5, iops5 = CalculateDiskStatistics( + zerodata, buff5, name) + diskLoad15, diskLoadPercent15, iops15 = CalculateDiskStatistics( + zerodata, buff15, name) + disksLoadAvg[name] = [diskLoad1, diskLoad5, diskLoad15] + disksLoadPercentAvg[name] = [diskLoadPercent1, + diskLoadPercent5, diskLoadPercent15] + iopsAvg[name] = [iops1, iops5, iops15] + # end fore + + # save statistics + statistics = local.db.get("statistics", dict()) + statistics["disksLoadAvg"] = disksLoadAvg + statistics["disksLoadPercentAvg"] = disksLoadPercentAvg + statistics["iopsAvg"] = iopsAvg + local.db["statistics"] = statistics +# end define + + +def CalculateDiskStatistics(zerodata, data, name): + if data is None: + return None, None, None + data = data[name] + zerodata = zerodata[name] + timeDiff = zerodata["timestamp"] - data["timestamp"] + busyTimeDiff = zerodata["busyTime"] - data["busyTime"] + diskReadDiff = zerodata["readBytes"] - data["readBytes"] + diskWriteDiff = zerodata["writeBytes"] - data["writeBytes"] + diskReadCountDiff = zerodata["readCount"] - data["readCount"] + diskWriteCountDiff = zerodata["writeCount"] - data["writeCount"] + diskLoadPercent = busyTimeDiff / 1000 / timeDiff * \ + 100 # /1000 - to second, *100 - to percent + diskLoadPercent = round(diskLoadPercent, 2) + diskRead = diskReadDiff / timeDiff + diskWrite = diskWriteDiff / timeDiff + diskReadCount = diskReadCountDiff / timeDiff + diskWriteCount = diskWriteCountDiff / timeDiff + diskLoad = b2mb(diskRead + diskWrite) + iops = round(diskReadCount + diskWriteCount, 2) + return diskLoad, diskLoadPercent, iops +# end define + + +def GetDisksList(): + data = list() + buff = os.listdir("/sys/block/") + for item in buff: + if "loop" in item: + continue + data.append(item) + # end for + data.sort() + return data +# end define + + +def ReadNetworkData(local): + timestamp = get_timestamp() + interfaceName = get_internet_interface_name() + buff = psutil.net_io_counters(pernic=True) + buff = buff[interfaceName] + data = dict() + data["timestamp"] = timestamp + data["bytesRecv"] = buff.bytes_recv + data["bytesSent"] = buff.bytes_sent + data["packetsSent"] = buff.packets_sent + data["packetsRecv"] = buff.packets_recv + + local.buffer.network.pop(0) + local.buffer.network.append(data) +# end define + + +def SaveNetworkStatistics(local): + data = local.buffer.network + data = data[::-1] + zerodata = data[0] + buff1 = data[1*6-1] + buff5 = data[5*6-1] + buff15 = data[15*6-1] + if buff5 is None: + buff5 = buff1 + if buff15 is None: + buff15 = buff5 + # end if + + netLoadAvg = dict() + ppsAvg = dict() + networkLoadAvg1, ppsAvg1 = CalculateNetworkStatistics(zerodata, buff1) + networkLoadAvg5, ppsAvg5 = CalculateNetworkStatistics(zerodata, buff5) + networkLoadAvg15, ppsAvg15 = CalculateNetworkStatistics(zerodata, buff15) + netLoadAvg = [networkLoadAvg1, networkLoadAvg5, networkLoadAvg15] + ppsAvg = [ppsAvg1, ppsAvg5, ppsAvg15] + + # save statistics + statistics = local.db.get("statistics", dict()) + statistics["netLoadAvg"] = netLoadAvg + statistics["ppsAvg"] = ppsAvg + local.db["statistics"] = statistics +# end define + + +def CalculateNetworkStatistics(zerodata, data): + if data is None: + return None, None + timeDiff = zerodata["timestamp"] - data["timestamp"] + bytesRecvDiff = zerodata["bytesRecv"] - data["bytesRecv"] + bytesSentDiff = zerodata["bytesSent"] - data["bytesSent"] + packetsRecvDiff = zerodata["packetsRecv"] - data["packetsRecv"] + packetsSentDiff = zerodata["packetsSent"] - data["packetsSent"] + bitesRecvAvg = bytesRecvDiff / timeDiff * 8 + bitesSentAvg = bytesSentDiff / timeDiff * 8 + packetsRecvAvg = packetsRecvDiff / timeDiff + packetsSentAvg = packetsSentDiff / timeDiff + netLoadAvg = b2mb(bitesRecvAvg + bitesSentAvg) + ppsAvg = round(packetsRecvAvg + packetsSentAvg, 2) + return netLoadAvg, ppsAvg +# end define + + +def ReadTransData(local, scanner): + transData = local.buffer.transData + SetToTimeData(transData, scanner.transNum) + ShortTimeData(transData) +# end define + + +def SetToTimeData(timeDataList, data): + timenow = int(time.time()) + timeDataList[timenow] = data +# end define + + +def ShortTimeData(data, max=120, diff=20): + if len(data) < max: + return + buff = data.copy() + data.clear() + keys = sorted(buff.keys(), reverse=True) + for item in keys[:max-diff]: + data[item] = buff[item] +# end define + + +def SaveTransStatistics(local): + tps1 = GetTps(local, 60) + tps5 = GetTps(local, 60*5) + tps15 = GetTps(local, 60*15) + + # save statistics + statistics = local.db.get("statistics", dict()) + statistics["tpsAvg"] = [tps1, tps5, tps15] + local.db["statistics"] = statistics +# end define + + +def GetDataPerSecond(data, timediff): + if len(data) == 0: + return + timenow = sorted(data.keys())[-1] + now = data.get(timenow) + prev = GetItemFromTimeData(data, timenow-timediff) + if prev is None: + return + diff = now - prev + result = diff / timediff + result = round(result, 2) + return result +# end define + + +def GetItemFromTimeData(data, timeneed): + if timeneed in data: + result = data.get(timeneed) + else: + result = data[min(data.keys(), key=lambda k: abs(k-timeneed))] + return result +# end define + + +def GetTps(local, timediff): + data = local.buffer.transData + tps = GetDataPerSecond(data, timediff) + return tps +# end define + + +def GetBps(local, timediff): + data = local.buffer.blocksData + bps = GetDataPerSecond(data, timediff) + return bps +# end define + + +def GetBlockTimeAvg(local, timediff): + bps = GetBps(local, timediff) + if bps is None or bps == 0: + return + result = 1/bps + result = round(result, 2) + return result +# end define + + +def Offers(local, ton): + saveOffers = ton.GetSaveOffers() + offers = ton.GetOffers() + for offer in offers: + offerHash = offer.get("hash") + if offerHash in saveOffers: + ton.VoteOffer(offerHash) +# end define + + +def Domains(local, ton): + pass +# end define + + +def GetUname(): + data = os.uname() + result = dict( + zip('sysname nodename release version machine'.split(), data)) + result.pop("nodename") + return result +# end define + + +def GetMemoryInfo(): + result = dict() + data = psutil.virtual_memory() + result["total"] = round(data.total / 10**9, 2) + result["usage"] = round(data.used / 10**9, 2) + result["usagePercent"] = data.percent + return result +# end define + + +def GetSwapInfo(): + result = dict() + data = psutil.swap_memory() + result["total"] = round(data.total / 10**9, 2) + result["usage"] = round(data.used / 10**9, 2) + result["usagePercent"] = data.percent + return result +# end define + + +def GetValidatorProcessInfo(): + pid = get_service_pid("validator") + if pid == None or pid == 0: + return + p = psutil.Process(pid) + mem = p.memory_info() + result = dict() + result["cpuPercent"] = p.cpu_percent() + memory = dict() + memory["rss"] = mem.rss + memory["vms"] = mem.vms + memory["shared"] = mem.shared + memory["text"] = mem.text + memory["lib"] = mem.lib + memory["data"] = mem.data + memory["dirty"] = mem.dirty + result["memory"] = memory + # io = p.io_counters() # Permission denied: '/proc/{pid}/io' + return result +# end define + + +def Telemetry(local, ton): + sendTelemetry = local.db.get("sendTelemetry") + if sendTelemetry is not True: + return + # end if + + # Get validator status + data = dict() + data["adnlAddr"] = ton.GetAdnlAddr() + data["validatorStatus"] = ton.GetValidatorStatus() + data["cpuNumber"] = psutil.cpu_count() + data["cpuLoad"] = get_load_avg() + data["netLoad"] = ton.GetStatistics("netLoadAvg") + data["tps"] = ton.GetStatistics("tpsAvg") + data["disksLoad"] = ton.GetStatistics("disksLoadAvg") + data["disksLoadPercent"] = ton.GetStatistics("disksLoadPercentAvg") + data["iops"] = ton.GetStatistics("iopsAvg") + data["pps"] = ton.GetStatistics("ppsAvg") + data["dbUsage"] = ton.GetDbUsage() + data["memory"] = GetMemoryInfo() + data["swap"] = GetSwapInfo() + data["uname"] = GetUname() + data["vprocess"] = GetValidatorProcessInfo() + elections = local.try_function(ton.GetElectionEntries) + complaints = local.try_function(ton.GetComplaints) + + # Get git hashes + gitHashes = dict() + gitHashes["mytonctrl"] = get_git_hash("/usr/src/mytonctrl") + gitHashes["validator"] = GetBinGitHash( + "/usr/bin/ton/validator-engine/validator-engine") + data["gitHashes"] = gitHashes + data["stake"] = local.db.get("stake") + + # Get validator config + vconfig = ton.GetValidatorConfig() + data["fullnode_adnl"] = vconfig.fullnode + + # Send data to toncenter server + liteUrl_default = "https://telemetry.toncenter.com/report_status" + liteUrl = local.db.get("telemetryLiteUrl", liteUrl_default) + output = json.dumps(data) + resp = requests.post(liteUrl, data=output, timeout=3) +# end define + + +def GetBinGitHash(path, short=False): + if not os.path.isfile(path): + return + args = [path, "--version"] + process = subprocess.run(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + output = process.stdout.decode("utf-8") + if "build information" not in output: + return + buff = output.split(' ') + start = buff.index("Commit:") + 1 + result = buff[start].replace(',', '') + if short is True: + result = result[:7] + return result +# end define + + +def OverlayTelemetry(local, ton): + sendTelemetry = local.db.get("sendTelemetry") + if sendTelemetry is not True: + return + # end if + + # Get validator status + data = dict() + data["adnlAddr"] = ton.GetAdnlAddr() + data["overlaysStats"] = ton.GetOverlaysStats() + + # Send data to toncenter server + overlayUrl_default = "https://telemetry.toncenter.com/report_overlays" + overlayUrl = local.db.get("overlayTelemetryUrl", overlayUrl_default) + output = json.dumps(data) + resp = requests.post(overlayUrl, data=output, timeout=3) +# end define + + +def Complaints(local, ton): + validatorIndex = ton.GetValidatorIndex() + if validatorIndex < 0: + return + # end if + + # Voting for complaints + config32 = ton.GetConfig32() + electionId = config32.get("startWorkTime") + complaintsHashes = ton.SaveComplaints(electionId) + complaints = ton.GetComplaints(electionId) + for key, item in complaints.items(): + complaintHash = item.get("hash") + complaintHash_hex = Dec2HexAddr(complaintHash) + if complaintHash_hex in complaintsHashes: + ton.VoteComplaint(electionId, complaintHash) +# end define + + +def Slashing(local, ton): + isSlashing = local.db.get("isSlashing") + if isSlashing is not True: + return + # end if + + # Creating complaints + slash_time = local.buffer.slash_time + config32 = ton.GetConfig32() + start = config32.get("startWorkTime") + end = config32.get("endWorkTime") + local.add_log("slash_time {}, start {}, end {}".format(slash_time, start, end), "debug") + if slash_time != start: + end -= 60 + ton.CheckValidators(start, end) + local.buffer.slash_time = start +# end define + + +def ScanLiteServers(local, ton): + # Считать список серверов + filePath = ton.liteClient.configPath + file = open(filePath, 'rt') + text = file.read() + file.close() + data = json.loads(text) + + # Пройтись по серверам + result = list() + liteservers = data.get("liteservers") + for index in range(len(liteservers)): + try: + ton.liteClient.Run("last", index=index) + result.append(index) + except: + pass + # end for + + # Записать данные в базу + local.db["liteServers"] = result +# end define + + +def General(local): + local.add_log("start General function", "debug") + ton = MyTonCore(local) + scanner = Dict() + # scanner.Run() + + # Запустить потоки + local.start_cycle(Elections, sec=600, args=(local, ton, )) + local.start_cycle(Statistics, sec=10, args=(local, )) + local.start_cycle(Offers, sec=600, args=(local, ton, )) + local.start_cycle(Complaints, sec=600, args=(local, ton, )) + local.start_cycle(Slashing, sec=600, args=(local, ton, )) + local.start_cycle(Domains, sec=600, args=(local, ton, )) + local.start_cycle(Telemetry, sec=60, args=(local, ton, )) + local.start_cycle(OverlayTelemetry, sec=7200, args=(local, ton, )) + local.start_cycle(ScanLiteServers, sec=60, args=(local, ton,)) + thr_sleep() +# end define + + +def mytoncore(): + from mypylib.mypylib import MyPyClass + + local = MyPyClass('mytoncore.py') + print('Local DB path:', local.buffer['localdbFileName']) + Init(local) + General(local) diff --git a/mytoncore/liteclient.py b/mytoncore/liteclient.py new file mode 100644 index 00000000..8a7a25df --- /dev/null +++ b/mytoncore/liteclient.py @@ -0,0 +1,44 @@ +import random +import subprocess + + +class LiteClient: + def __init__(self, local): + self.local = local + self.appPath = None + self.configPath = None + self.pubkeyPath = None + self.addr = None + self.ton = None # magic + #end define + + def Run(self, cmd, **kwargs): + index = kwargs.get("index") + liteclient_timeout = self.local.db.liteclient_timeout if self.local.db.liteclient_timeout else 3 + timeout = kwargs.get("timeout", liteclient_timeout) + useLocalLiteServer = kwargs.get("useLocalLiteServer", True) + validatorStatus = self.ton.GetValidatorStatus() + validatorOutOfSync = validatorStatus.get("outOfSync") + args = [self.appPath, "--global-config", self.configPath, "--verbosity", "0", "--cmd", cmd] + if index is not None: + index = str(index) + args += ["-i", index] + elif useLocalLiteServer and self.pubkeyPath and validatorOutOfSync < 20: + args = [self.appPath, "--addr", self.addr, "--pub", self.pubkeyPath, "--verbosity", "0", "--cmd", cmd] + else: + liteServers = self.local.db.get("liteServers") + if liteServers is not None and len(liteServers): + index = random.choice(liteServers) + index = str(index) + args += ["-i", index] + #end if + + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + output = process.stdout.decode("utf-8") + err = process.stderr.decode("utf-8") + if len(err) > 0: + self.local.add_log("args: {args}".format(args=args), "error") + raise Exception("LiteClient error: {err}".format(err=err)) + return output + #end define +#end class diff --git a/mytoncore/models.py b/mytoncore/models.py new file mode 100644 index 00000000..474fa276 --- /dev/null +++ b/mytoncore/models.py @@ -0,0 +1,177 @@ +import os + + +class Wallet: + def __init__(self, name, path, version): + self.name = name + self.path = path + self.addrFilePath = f"{path}.addr" + self.privFilePath = f"{path}.pk" + self.bocFilePath = f"{path}-query.boc" + self.addrFull = None + self.workchain = None + self.addr = None + self.addrB64 = None + self.addrB64_init = None + self.oldseqno = None + self.account = None + self.subwallet = None + self.version = version + #end define + + def Delete(self): + os.remove(self.addrFilePath) + os.remove(self.privFilePath) + #end define +#end class + + +class Account: + def __init__(self, workchain, addr): + self.workchain = workchain + self.addr = addr + self.addrB64 = None + self.addrFull = None + self.status = "empty" + self.balance = 0 + self.lt = None + self.hash = None + self.codeHash = None + #end define +#end class + + +class Domain(dict): + def __init__(self): + self["name"] = None + self["adnlAddr"] = None + self["walletName"] = None + #end define +#end class + + +class Block(): + def __init__(self, str=None): + self.workchain = None + self.shardchain = None + self.seqno = None + self.rootHash = None + self.fileHash = None + self.ParsBlock(str) + #end define + + def ParsBlock(self, str): + if str is None: + return + buff = str.split(':') + self.rootHash = buff[1] + self.fileHash = buff[2] + buff = buff[0] + buff = buff.replace('(', '') + buff = buff.replace(')', '') + buff = buff.split(',') + self.workchain = int(buff[0]) + self.shardchain = buff[1] + self.seqno = int(buff[2]) + #end define + + def __str__(self): + result = f"({self.workchain},{self.shardchain},{self.seqno}):{self.rootHash}:{self.fileHash}" + return result + #end define + + def __repr__(self): + return self.__str__() + #end define + + def __eq__(self, other): + if other is None: + return False + return self.rootHash == other.rootHash and self.fileHash == other.fileHash + #end define +#end class + + +class Trans(): + def __init__(self, block, addr=None, lt=None, hash=None): + self.block = block + self.addr = addr + self.lt = lt + self.hash = hash + #end define + + def __str__(self): + return str(self.__dict__) + #end define + + def __repr__(self): + return self.__str__() + #end define + + def __eq__(self, other): + if other is None: + return False + return self.hash == other.hash + #end define +#end class + + +class Message(): + def __init__(self): + self.trans = None + self.type = None + self.time = None + self.srcWorkchain = None + self.destWorkchain = None + self.srcAddr = None + self.destAddr = None + self.value = None + self.body = None + self.comment = None + self.ihr_fee = None + self.fwd_fee = None + self.total_fees = None + self.ihr_disabled = None + self.hash = None + #end define + + def GetFullAddr(self, workchain, addr): + if addr is None: + return + return f"{workchain}:{addr}" + #end define + + def __str__(self): + return str(self.__dict__) + #end define + + def __repr__(self): + return self.__str__() + #end define + + def __eq__(self, other): + if other is None: + return False + return self.hash == other.hash + #end define +#end class + + +class Pool: + def __init__(self, name, path): + self.name = name + self.path = path + self.addrFilePath = f"{path}.addr" + self.bocFilePath = f"{path}-query.boc" + self.addrFull = None + self.workchain = None + self.addr = None + self.addrB64 = None + self.addrB64_init = None + self.account = None + #end define + + def Delete(self): + os.remove(self.addrFilePath) + #end define +#end class diff --git a/mytoncore.py b/mytoncore/mytoncore.py old mode 100755 new mode 100644 similarity index 75% rename from mytoncore.py rename to mytoncore/mytoncore.py index fd1a9671..e912adf3 --- a/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1,274 +1,42 @@ -#!/usr/bin/env python3 -# -*- coding: utf_8 -*-l - -from fastcrc import crc16 -import struct -import random -import hashlib -import requests +import os +import base64 +import time import re -from mypylib.mypylib import * - -local = MyPyClass(__file__) - -class LiteClient: - def __init__(self): - self.appPath = None - self.configPath = None - self.pubkeyPath = None - self.addr = None - self.ton = None # magic - #end define - - def Run(self, cmd, **kwargs): - index = kwargs.get("index") - liteclient_timeout = local.db.liteclient_timeout if local.db.liteclient_timeout else 3 - timeout = kwargs.get("timeout", liteclient_timeout) - useLocalLiteServer = kwargs.get("useLocalLiteServer", True) - validatorStatus = self.ton.GetValidatorStatus() - validatorOutOfSync = validatorStatus.get("outOfSync") - args = [self.appPath, "--global-config", self.configPath, "--verbosity", "0", "--cmd", cmd] - if index is not None: - index = str(index) - args += ["-i", index] - elif useLocalLiteServer and self.pubkeyPath and validatorOutOfSync < 20: - args = [self.appPath, "--addr", self.addr, "--pub", self.pubkeyPath, "--verbosity", "0", "--cmd", cmd] - else: - liteServers = local.db.get("liteServers") - if liteServers is not None and len(liteServers): - index = random.choice(liteServers) - index = str(index) - args += ["-i", index] - #end if - - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) - output = process.stdout.decode("utf-8") - err = process.stderr.decode("utf-8") - if len(err) > 0: - local.add_log("args: {args}".format(args=args), "error") - raise Exception("LiteClient error: {err}".format(err=err)) - return output - #end define -#end class - -class ValidatorConsole: - def __init__(self): - self.appPath = None - self.privKeyPath = None - self.pubKeyPath = None - self.addr = None - #end define - - def Run(self, cmd, **kwargs): - console_timeout = local.db.console_timeout if local.db.console_timeout else 3 - timeout = kwargs.get("timeout", console_timeout) - if self.appPath is None or self.privKeyPath is None or self.pubKeyPath is None: - raise Exception("ValidatorConsole error: Validator console is not settings") - args = [self.appPath, "-k", self.privKeyPath, "-p", self.pubKeyPath, "-a", self.addr, "-v", "0", "--cmd", cmd] - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) - output = process.stdout.decode("utf-8") - err = process.stderr.decode("utf-8") - if len(err) > 0: - local.add_log("args: {args}".format(args=args), "error") - raise Exception("ValidatorConsole error: {err}".format(err=err)) - return output - #end define -#end class - -class Fift: - def __init__(self): - self.appPath = None - self.libsPath = None - self.smartcontsPath = None - #end define - - def Run(self, args, **kwargs): - fift_timeout = local.db.fift_timeout if local.db.fift_timeout else 3 - timeout = kwargs.get("timeout", fift_timeout) - for i in range(len(args)): - args[i] = str(args[i]) - includePath = self.libsPath + ':' + self.smartcontsPath - args = [self.appPath, "-I", includePath, "-s"] + args - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) - output = process.stdout.decode("utf-8") - err = process.stderr.decode("utf-8") - if len(err) > 0: - local.add_log("args: {args}".format(args=args), "error") - raise Exception("Fift error: {err}".format(err=err)) - return output - #end define -#end class - -class Wallet: - def __init__(self, name, path, version): - self.name = name - self.path = path - self.addrFilePath = f"{path}.addr" - self.privFilePath = f"{path}.pk" - self.bocFilePath = f"{path}-query.boc" - self.addrFull = None - self.workchain = None - self.addr = None - self.addrB64 = None - self.addrB64_init = None - self.oldseqno = None - self.account = None - self.subwallet = None - self.version = version - #end define - - def Delete(self): - os.remove(self.addrFilePath) - os.remove(self.privFilePath) - #end define -#end class - -class Account: - def __init__(self, workchain, addr): - self.workchain = workchain - self.addr = addr - self.addrB64 = None - self.addrFull = None - self.status = "empty" - self.balance = 0 - self.lt = None - self.hash = None - self.codeHash = None - #end define -#end class - -class Domain(dict): - def __init__(self): - self["name"] = None - self["adnlAddr"] = None - self["walletName"] = None - #end define -#end class - -class Block(): - def __init__(self, str=None): - self.workchain = None - self.shardchain = None - self.seqno = None - self.rootHash = None - self.fileHash = None - self.ParsBlock(str) - #end define - - def ParsBlock(self, str): - if str is None: - return - buff = str.split(':') - self.rootHash = buff[1] - self.fileHash = buff[2] - buff = buff[0] - buff = buff.replace('(', '') - buff = buff.replace(')', '') - buff = buff.split(',') - self.workchain = int(buff[0]) - self.shardchain = buff[1] - self.seqno = int(buff[2]) - #end define - - def __str__(self): - result = f"({self.workchain},{self.shardchain},{self.seqno}):{self.rootHash}:{self.fileHash}" - return result - #end define - - def __repr__(self): - return self.__str__() - #end define - - def __eq__(self, other): - if other is None: - return False - return self.rootHash == other.rootHash and self.fileHash == other.fileHash - #end define -#end class - -class Trans(): - def __init__(self, block, addr=None, lt=None, hash=None): - self.block = block - self.addr = addr - self.lt = lt - self.hash = hash - #end define - - def __str__(self): - return str(self.__dict__) - #end define - - def __repr__(self): - return self.__str__() - #end define - - def __eq__(self, other): - if other is None: - return False - return self.hash == other.hash - #end define -#end class - -class Message(): - def __init__(self): - self.trans = None - self.type = None - self.time = None - self.srcWorkchain = None - self.destWorkchain = None - self.srcAddr = None - self.destAddr = None - self.value = None - self.body = None - self.comment = None - self.ihr_fee = None - self.fwd_fee = None - self.total_fees = None - self.ihr_disabled = None - #end define - - def GetFullAddr(self, workchain, addr): - if addr is None: - return - return f"{workchain}:{addr}" - #end define - - def __str__(self): - return str(self.__dict__) - #end define +import json +import hashlib +import struct +import psutil +import crc16 # TODO: check this library! +import fastcrc +import subprocess - def __repr__(self): - return self.__str__() - #end define +from fastcrc import crc16 - def __eq__(self, other): - if other is None: - return False - return self.hash == other.hash - #end define -#end class +from mytoncore.utils import xhex2hex, ng2g +from mytoncore.liteclient import LiteClient +from mytoncore.validator_console import ValidatorConsole +from mytoncore.fift import Fift +from mytoncore.models import ( + Wallet, + Account, + Domain, + Block, + Trans, + Message, + Pool, +) + +from mypylib.mypylib import ( + parse, + get_timestamp, + timestamp2datetime, + dec2hex, +) -class Pool: - def __init__(self, name, path): - self.name = name - self.path = path - self.addrFilePath = f"{path}.addr" - self.bocFilePath = f"{path}-query.boc" - self.addrFull = None - self.workchain = None - self.addr = None - self.addrB64 = None - self.addrB64_init = None - self.account = None - #end define - - def Delete(self): - os.remove(self.addrFilePath) - #end define -#end class class MyTonCore(): - def __init__(self): + def __init__(self, local): + self.local = local self.walletsDir = None self.dbFile = None self.contractsDir = None @@ -276,9 +44,9 @@ def __init__(self): self.tempDir = None self.nodeName = None - self.liteClient = LiteClient() - self.validatorConsole = ValidatorConsole() - self.fift = Fift() + self.liteClient = LiteClient(self.local) + self.validatorConsole = ValidatorConsole(self.local) + self.fift = Fift(self.local) self.Refresh() self.Init() @@ -293,22 +61,21 @@ def Init(self): def Refresh(self): if self.dbFile: - local.load_db(self.dbFile) - #end if + self.local.load_db(self.dbFile) if not self.walletsDir: - self.walletsDir = local.buffer.my_work_dir + "wallets/" - self.contractsDir = local.buffer.my_work_dir + "contracts/" - self.poolsDir = local.buffer.my_work_dir + "pools/" - self.tempDir = local.buffer.my_temp_dir + self.walletsDir = self.local.buffer.my_work_dir + "wallets/" + self.contractsDir = self.local.buffer.my_work_dir + "contracts/" + self.poolsDir = self.local.buffer.my_work_dir + "pools/" + self.tempDir = self.local.buffer.my_work_dir - self.nodeName = local.db.get("nodeName") + self.nodeName = self.local.db.get("nodeName") if self.nodeName is None: self.nodeName="" else: self.nodeName = self.nodeName + "_" - liteClient = local.db.get("liteClient") + liteClient = self.local.db.get("liteClient") if liteClient is not None: self.liteClient.ton = self # magic self.liteClient.appPath = liteClient["appPath"] @@ -319,7 +86,7 @@ def Refresh(self): self.liteClient.addr = "{0}:{1}".format(liteServer["ip"], liteServer["port"]) #end if - validatorConsole = local.db.get("validatorConsole") + validatorConsole = self.local.db.get("validatorConsole") if validatorConsole is not None: self.validatorConsole.appPath = validatorConsole["appPath"] self.validatorConsole.privKeyPath = validatorConsole["privKeyPath"] @@ -327,7 +94,7 @@ def Refresh(self): self.validatorConsole.addr = validatorConsole["addr"] #end if - fift = local.db.get("fift") + fift = self.local.db.get("fift") if fift is not None: self.fift.appPath = fift["appPath"] self.fift.libsPath = fift["libsPath"] @@ -339,18 +106,18 @@ def Refresh(self): #end define def CheckConfigFile(self, fift, liteClient): - mconfig_path = local.buffer.db_path + mconfig_path = self.local.buffer.db_path backup_path = mconfig_path + ".backup" if fift is None or liteClient is None: - local.add_log("The config file is broken", "warning") - print(f"local.db: {local.db}") + self.local.add_log("The config file is broken", "warning") + print(f"self.local.db: {self.local.db}") if os.path.isfile(backup_path): - local.add_log("Restoring the configuration file", "info") + self.local.add_log("Restoring the configuration file", "info") args = ["cp", backup_path, mconfig_path] subprocess.run(args) self.Refresh() elif os.path.isfile(backup_path) == False: - local.add_log("Create backup config file", "info") + self.local.add_log("Create backup config file", "info") args = ["cp", mconfig_path, backup_path] subprocess.run(args) #end define @@ -387,7 +154,7 @@ def GetVarFromWorkerOutput(self, text, search): #end define def GetSeqno(self, wallet): - local.add_log("start GetSeqno function", "debug") + self.local.add_log("start GetSeqno function", "debug") cmd = "runmethodfull {addr} seqno".format(addr=wallet.addrB64) result = self.liteClient.Run(cmd) if "cannot run any methods" in result: @@ -402,7 +169,7 @@ def GetSeqno(self, wallet): #end define def GetAccount(self, inputAddr): - #local.add_log("start GetAccount function", "debug") + #self.local.add_log("start GetAccount function", "debug") workchain, addr = self.ParseInputAddr(inputAddr) account = Account(workchain, addr) cmd = "getaccount {inputAddr}".format(inputAddr=inputAddr) @@ -447,7 +214,7 @@ def GetCodeHash(self, code): #end define def GetAccountHistory(self, account, limit): - local.add_log("start GetAccountHistory function", "debug") + self.local.add_log("start GetAccountHistory function", "debug") addr = f"{account.workchain}:{account.addr}" lt = account.lt transHash = account.hash @@ -636,7 +403,7 @@ def GetDomainAddr(self, domainName): #end define def GetDomainEndTime(self, domainName): - local.add_log("start GetDomainEndTime function", "debug") + self.local.add_log("start GetDomainEndTime function", "debug") buff = domainName.split('.') subdomain = buff.pop(0) dnsDomain = ".".join(buff) @@ -652,7 +419,7 @@ def GetDomainEndTime(self, domainName): #end define def GetDomainAdnlAddr(self, domainName): - local.add_log("start GetDomainAdnlAddr function", "debug") + self.local.add_log("start GetDomainAdnlAddr function", "debug") cmd = "dnsresolve {domainName} 1".format(domainName=domainName) result = self.liteClient.Run(cmd) lines = result.split('\n') @@ -665,7 +432,7 @@ def GetDomainAdnlAddr(self, domainName): #end define def GetLocalWallet(self, walletName, version=None, subwallet=None): - local.add_log("start GetLocalWallet function", "debug") + self.local.add_log("start GetLocalWallet function", "debug") if walletName is None: return None walletPath = self.walletsDir + walletName @@ -677,7 +444,7 @@ def GetLocalWallet(self, walletName, version=None, subwallet=None): #end define def GetWalletFromFile(self, filePath, version): - local.add_log("start GetWalletFromFile function", "debug") + self.local.add_log("start GetWalletFromFile function", "debug") # Check input args if (".addr" in filePath): filePath = filePath.replace(".addr", '') @@ -696,7 +463,7 @@ def GetWalletFromFile(self, filePath, version): #end define def GetHighWalletFromFile(self, filePath, subwallet, version): - local.add_log("start GetHighWalletFromFile function", "debug") + self.local.add_log("start GetHighWalletFromFile function", "debug") # Check input args if (".addr" in filePath): filePath = filePath.replace(".addr", '') @@ -728,7 +495,7 @@ def AddrFile2Object(self, object): #end define def WalletVersion2Wallet(self, wallet): - local.add_log("start WalletVersion2Wallet function", "debug") + self.local.add_log("start WalletVersion2Wallet function", "debug") if wallet.version is not None: return walletsVersionList = self.GetWalletsVersionList() @@ -737,7 +504,7 @@ def WalletVersion2Wallet(self, wallet): if version is None: version = self.GetWalletVersionFromHash(account.codeHash) if version is None: - local.add_log("Wallet version not found: " + wallet.addrB64, "warning") + self.local.add_log("Wallet version not found: " + wallet.addrB64, "warning") return #end if @@ -748,11 +515,11 @@ def WalletVersion2Wallet(self, wallet): def SetWalletVersion(self, addrB64, version): walletsVersionList = self.GetWalletsVersionList() walletsVersionList[addrB64] = version - local.save() + self.local.save() #end define def GetWalletVersionFromHash(self, inputHash): - local.add_log("start GetWalletVersionFromHash function", "debug") + self.local.add_log("start GetWalletVersionFromHash function", "debug") arr = dict() arr["v1r1"] = "d670136510daff4fee1889b8872c4c1e89872ffa1fe58a23a5f5d99cef8edf32" arr["v1r2"] = "2705a31a7ac162295c8aed0761cc6e031ab65521dd7b4a14631099e02de99e18" @@ -771,10 +538,10 @@ def GetWalletVersionFromHash(self, inputHash): def GetWalletsVersionList(self): bname = "walletsVersionList" - walletsVersionList = local.db.get(bname) + walletsVersionList = self.local.db.get(bname) if walletsVersionList is None: walletsVersionList = dict() - local.db[bname] = walletsVersionList + self.local.db[bname] = walletsVersionList return walletsVersionList #end define @@ -786,7 +553,7 @@ def GetFullConfigAddr(self): return buff #end if - local.add_log("start GetFullConfigAddr function", "debug") + self.local.add_log("start GetFullConfigAddr function", "debug") result = self.liteClient.Run("getconfig 0") configAddr_hex = self.GetVarFromWorkerOutput(result, "config_addr:x") fullConfigAddr = "-1:{configAddr_hex}".format(configAddr_hex=configAddr_hex) @@ -805,7 +572,7 @@ def GetFullElectorAddr(self): #end if # Get data - local.add_log("start GetFullElectorAddr function", "debug") + self.local.add_log("start GetFullElectorAddr function", "debug") result = self.liteClient.Run("getconfig 1") electorAddr_hex = self.GetVarFromWorkerOutput(result, "elector_addr:x") fullElectorAddr = "-1:{electorAddr_hex}".format(electorAddr_hex=electorAddr_hex) @@ -823,7 +590,7 @@ def GetFullMinterAddr(self): return buff #end if - local.add_log("start GetFullMinterAddr function", "debug") + self.local.add_log("start GetFullMinterAddr function", "debug") result = self.liteClient.Run("getconfig 2") minterAddr_hex = self.GetVarFromWorkerOutput(result, "minter_addr:x") fullMinterAddr = "-1:{minterAddr_hex}".format(minterAddr_hex=minterAddr_hex) @@ -841,7 +608,7 @@ def GetFullDnsRootAddr(self): return buff #end if - local.add_log("start GetFullDnsRootAddr function", "debug") + self.local.add_log("start GetFullDnsRootAddr function", "debug") result = self.liteClient.Run("getconfig 4") dnsRootAddr_hex = self.GetVarFromWorkerOutput(result, "dns_root_addr:x") fullDnsRootAddr = "-1:{dnsRootAddr_hex}".format(dnsRootAddr_hex=dnsRootAddr_hex) @@ -859,7 +626,7 @@ def GetActiveElectionId(self, fullElectorAddr): return buff #end if - local.add_log("start GetActiveElectionId function", "debug") + self.local.add_log("start GetActiveElectionId function", "debug") cmd = "runmethodfull {fullElectorAddr} active_election_id".format(fullElectorAddr=fullElectorAddr) result = self.liteClient.Run(cmd) activeElectionId = self.GetVarFromWorkerOutput(result, "result") @@ -873,26 +640,26 @@ def GetActiveElectionId(self, fullElectorAddr): #end define def GetValidatorsElectedFor(self): - local.add_log("start GetValidatorsElectedFor function", "debug") + self.local.add_log("start GetValidatorsElectedFor function", "debug") config15 = self.GetConfig15() return config15["validatorsElectedFor"] #end define def GetMinStake(self): - local.add_log("start GetMinStake function", "debug") + self.local.add_log("start GetMinStake function", "debug") config17 = self.GetConfig17() return config17["minStake"] #end define def GetRootWorkchainEnabledTime(self): - local.add_log("start GetRootWorkchainEnabledTime function", "debug") + self.local.add_log("start GetRootWorkchainEnabledTime function", "debug") config12 = self.GetConfig(12) enabledTime = config12["workchains"]["root"]["node"]["value"]["enabled_since"] return enabledTime #end define def GetTotalValidators(self): - local.add_log("start GetTotalValidators function", "debug") + self.local.add_log("start GetTotalValidators function", "debug") config34 = self.GetConfig34() result = config34["totalValidators"] return result @@ -1036,7 +803,7 @@ def GetValidatorStatus(self): return buff #end if - # local.add_log("start GetValidatorStatus function", "debug") + self.local.add_log("start GetValidatorStatus function", "debug") validatorStatus = dict() try: validatorStatus["isWorking"] = True @@ -1053,11 +820,11 @@ def GetValidatorStatus(self): validatorStatus["keymasterchainblock"] = self.GVS_GetItemFromBuff(buff) buff = parse(result, "rotatemasterchainblock", '\n') validatorStatus["rotatemasterchainblock"] = self.GVS_GetItemFromBuff(buff) - validatorStatus["transNum"] = local.buffer.get("transNum", -1) - validatorStatus["blocksNum"] = local.buffer.get("blocksNum", -1) - validatorStatus["masterBlocksNum"] = local.buffer.get("masterBlocksNum", -1) + validatorStatus["transNum"] = self.local.buffer.get("transNum", -1) + validatorStatus["blocksNum"] = self.local.buffer.get("blocksNum", -1) + validatorStatus["masterBlocksNum"] = self.local.buffer.get("masterBlocksNum", -1) except Exception as ex: - local.add_log(f"GetValidatorStatus warning: {ex}", "warning") + self.local.add_log(f"GetValidatorStatus warning: {ex}", "warning") validatorStatus["isWorking"] = False validatorStatus["unixtime"] = get_timestamp() validatorStatus["masterchainblocktime"] = 0 @@ -1089,7 +856,7 @@ def GetConfig(self, configId): #end if text = "start GetConfig function ({})".format(configId) - local.add_log(text, "debug") + self.local.add_log(text, "debug") cmd = "getconfig {configId}".format(configId=configId) result = self.liteClient.Run(cmd) start = result.find("ConfigParam") @@ -1128,7 +895,7 @@ def GetConfig32(self): return buff #end if - local.add_log("start GetConfig32 function", "debug") + self.local.add_log("start GetConfig32 function", "debug") config32 = dict() result = self.liteClient.Run("getconfig 32") config32["totalValidators"] = int(parse(result, "total:", ' ')) @@ -1164,7 +931,7 @@ def GetConfig34(self): return buff #end if - local.add_log("start GetConfig34 function", "debug") + self.local.add_log("start GetConfig34 function", "debug") config34 = dict() result = self.liteClient.Run("getconfig 34") config34["totalValidators"] = int(parse(result, "total:", ' ')) @@ -1201,7 +968,7 @@ def GetConfig36(self): return buff #end if - local.add_log("start GetConfig36 function", "debug") + self.local.add_log("start GetConfig36 function", "debug") config36 = dict() try: result = self.liteClient.Run("getconfig 36") @@ -1231,21 +998,21 @@ def GetConfig36(self): #end define def CreateNewKey(self): - local.add_log("start CreateNewKey function", "debug") + self.local.add_log("start CreateNewKey function", "debug") result = self.validatorConsole.Run("newkey") key = parse(result, "created new key ", '\n') return key #end define def GetPubKeyBase64(self, key): - local.add_log("start GetPubKeyBase64 function", "debug") + self.local.add_log("start GetPubKeyBase64 function", "debug") result = self.validatorConsole.Run("exportpub " + key) validatorPubkey_b64 = parse(result, "got public key: ", '\n') return validatorPubkey_b64 #end define def GetPubKey(self, key): - local.add_log("start GetPubKey function", "debug") + self.local.add_log("start GetPubKey function", "debug") pubkey_b64 = self.GetPubKeyBase64(key) buff = pubkey_b64.encode("utf-8") buff = base64.b64decode(buff) @@ -1256,7 +1023,7 @@ def GetPubKey(self, key): #end define def AddKeyToValidator(self, key, startWorkTime, endWorkTime): - local.add_log("start AddKeyToValidator function", "debug") + self.local.add_log("start AddKeyToValidator function", "debug") output = False cmd = "addpermkey {key} {startWorkTime} {endWorkTime}".format(key=key, startWorkTime=startWorkTime, endWorkTime=endWorkTime) result = self.validatorConsole.Run(cmd) @@ -1266,7 +1033,7 @@ def AddKeyToValidator(self, key, startWorkTime, endWorkTime): #end define def AddKeyToTemp(self, key, endWorkTime): - local.add_log("start AddKeyToTemp function", "debug") + self.local.add_log("start AddKeyToTemp function", "debug") output = False result = self.validatorConsole.Run("addtempkey {key} {key} {endWorkTime}".format(key=key, endWorkTime=endWorkTime)) if ("success" in result): @@ -1275,7 +1042,7 @@ def AddKeyToTemp(self, key, endWorkTime): #end define def AddAdnlAddrToValidator(self, adnlAddr): - local.add_log("start AddAdnlAddrToValidator function", "debug") + self.local.add_log("start AddAdnlAddrToValidator function", "debug") output = False result = self.validatorConsole.Run("addadnl {adnlAddr} 0".format(adnlAddr=adnlAddr)) if ("success" in result): @@ -1284,12 +1051,12 @@ def AddAdnlAddrToValidator(self, adnlAddr): #end define def GetAdnlAddr(self): - adnlAddr = local.db.get("adnlAddr") + adnlAddr = self.local.db.get("adnlAddr") return adnlAddr #end define def AttachAdnlAddrToValidator(self, adnlAddr, key, endWorkTime): - local.add_log("start AttachAdnlAddrToValidator function", "debug") + self.local.add_log("start AttachAdnlAddrToValidator function", "debug") output = False result = self.validatorConsole.Run("addvalidatoraddr {key} {adnlAddr} {endWorkTime}".format(adnlAddr=adnlAddr, key=key, endWorkTime=endWorkTime)) if ("success" in result): @@ -1298,7 +1065,7 @@ def AttachAdnlAddrToValidator(self, adnlAddr, key, endWorkTime): #end define def CreateConfigProposalRequest(self, offerHash, validatorIndex): - local.add_log("start CreateConfigProposalRequest function", "debug") + self.local.add_log("start CreateConfigProposalRequest function", "debug") fileName = self.tempDir + self.nodeName + "proposal_validator-to-sign.req" args = ["config-proposal-vote-req.fif", "-i", validatorIndex, offerHash, fileName] result = self.fift.Run(args) @@ -1316,7 +1083,7 @@ def CreateConfigProposalRequest(self, offerHash, validatorIndex): #end define def CreateComplaintRequest(self, electionId , complaintHash, validatorIndex): - local.add_log("start CreateComplaintRequest function", "debug") + self.local.add_log("start CreateComplaintRequest function", "debug") fileName = self.tempDir + "complaint_validator-to-sign.req" args = ["complaint-vote-req.fif", validatorIndex, electionId, complaintHash, fileName] result = self.fift.Run(args) @@ -1334,7 +1101,7 @@ def CreateComplaintRequest(self, electionId , complaintHash, validatorIndex): #end define def PrepareComplaint(self, electionId, inputFileName): - local.add_log("start PrepareComplaint function", "debug") + self.local.add_log("start PrepareComplaint function", "debug") fileName = self.tempDir + "complaint-msg-body.boc" args = ["envelope-complaint.fif", electionId, inputFileName, fileName] result = self.fift.Run(args) @@ -1343,7 +1110,7 @@ def PrepareComplaint(self, electionId, inputFileName): #end define def CreateElectionRequest(self, wallet, startWorkTime, adnlAddr, maxFactor): - local.add_log("start CreateElectionRequest function", "debug") + self.local.add_log("start CreateElectionRequest function", "debug") fileName = self.tempDir + self.nodeName + str(startWorkTime) + "_validator-to-sign.bin" args = ["validator-elect-req.fif", wallet.addrB64, startWorkTime, maxFactor, adnlAddr, fileName] result = self.fift.Run(args) @@ -1361,7 +1128,7 @@ def CreateElectionRequest(self, wallet, startWorkTime, adnlAddr, maxFactor): #end define def GetValidatorSignature(self, validatorKey, var1): - local.add_log("start GetValidatorSignature function", "debug") + self.local.add_log("start GetValidatorSignature function", "debug") cmd = "sign {validatorKey} {var1}".format(validatorKey=validatorKey, var1=var1) result = self.validatorConsole.Run(cmd) validatorSignature = parse(result, "got signature ", '\n') @@ -1369,7 +1136,7 @@ def GetValidatorSignature(self, validatorKey, var1): #end define def SignElectionRequestWithValidator(self, wallet, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor): - local.add_log("start SignElectionRequestWithValidator function", "debug") + self.local.add_log("start SignElectionRequestWithValidator function", "debug") fileName = self.tempDir + self.nodeName + str(startWorkTime) + "_validator-query.boc" args = ["validator-elect-signed.fif", wallet.addrB64, startWorkTime, maxFactor, adnlAddr, validatorPubkey_b64, validatorSignature, fileName] result = self.fift.Run(args) @@ -1379,7 +1146,7 @@ def SignElectionRequestWithValidator(self, wallet, startWorkTime, adnlAddr, vali #end define def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): - local.add_log("start SignBocWithWallet function", "debug") + self.local.add_log("start SignBocWithWallet function", "debug") flags = kwargs.get("flags", list()) subwalletDefault = 698983191 + wallet.workchain # 0x29A9A317 + workchain subwallet = kwargs.get("subwallet", subwalletDefault) @@ -1396,7 +1163,7 @@ def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): if bounceable == False and destAccount.status == "active": flags += ["-b"] text = "Find non-bounceable flag, but destination account already active. Using bounceable flag" - local.add_log(text, "warning") + self.local.AddLog(text, "warning") elif "-n" not in flags and bounceable == True and destAccount.status != "active": raise Exception("Find bounceable flag, but destination account is not active. Use non-bounceable address or flag -n") #end if @@ -1420,10 +1187,10 @@ def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): #end define def SendFile(self, filePath, wallet=None, **kwargs): - local.add_log("start SendFile function: " + filePath, "debug") + self.local.add_log("start SendFile function: " + filePath, "debug") timeout = kwargs.get("timeout", 30) remove = kwargs.get("remove", True) - duplicateSendfile = local.db.get("duplicateSendfile", True) + duplicateSendfile = self.local.db.get("duplicateSendfile", True) if not os.path.isfile(filePath): raise Exception("SendFile error: no such file '{filePath}'".format(filePath=filePath)) if timeout and wallet: @@ -1439,7 +1206,7 @@ def SendFile(self, filePath, wallet=None, **kwargs): #end define def WaitTransaction(self, wallet, timeout=30): - local.add_log("start WaitTransaction function", "debug") + self.local.add_log("start WaitTransaction function", "debug") timesleep = 3 steps = timeout // timesleep for i in range(steps): @@ -1451,7 +1218,7 @@ def WaitTransaction(self, wallet, timeout=30): #end define def GetReturnedStake(self, fullElectorAddr, inputAddr): - local.add_log("start GetReturnedStake function", "debug") + self.local.add_log("start GetReturnedStake function", "debug") workchain, addr = self.ParseInputAddr(inputAddr) cmd = f"runmethodfull {fullElectorAddr} compute_returned_stake 0x{addr}" result = self.liteClient.Run(cmd) @@ -1463,7 +1230,7 @@ def GetReturnedStake(self, fullElectorAddr, inputAddr): #end define def ProcessRecoverStake(self): - local.add_log("start ProcessRecoverStake function", "debug") + self.local.add_log("start ProcessRecoverStake function", "debug") resultFilePath = self.tempDir + self.nodeName + "recover-query" args = ["recover-stake.fif", resultFilePath] result = self.fift.Run(args) @@ -1472,9 +1239,9 @@ def ProcessRecoverStake(self): #end define def GetStake(self, account, args=None): - stake = local.db.get("stake") - usePool = local.db.get("usePool") - stakePercent = local.db.get("stakePercent", 99) + stake = self.local.db.get("stake") + usePool = self.local.db.get("usePool") + stakePercent = self.local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() config17 = self.GetConfig17() @@ -1489,7 +1256,7 @@ def GetStake(self, account, args=None): # Stake was a number stake = int(desiredStake) else: - local.add_log("Specified stake must be a percentage or whole number", "error") + self.local.add_log("Specified stake must be a percentage or whole number", "error") return # Limit stake to maximum available amount minus 10 (for transaction fees) @@ -1502,7 +1269,7 @@ def GetStake(self, account, args=None): if stake is None: sp = stakePercent / 100 if sp > 1 or sp < 0: - local.add_log("Wrong stakePercent value. Using default stake.", "warning") + self.local.add_log("Wrong stakePercent value. Using default stake.", "warning") elif len(vconfig.validators) == 0: stake = int(account.balance*sp/2) elif len(vconfig.validators) > 0: @@ -1512,15 +1279,15 @@ def GetStake(self, account, args=None): # Check if we have enough coins if stake > config17["maxStake"]: text = "Stake is greater than the maximum value. Will be used the maximum stake." - local.add_log(text, "warning") + self.local.add_log(text, "warning") stake = config17["maxStake"] if config17["minStake"] > stake: text = "Stake less than the minimum stake. Minimum stake: {minStake}".format(minStake=config17["minStake"]) - #local.add_log(text, "error") + # self.local.add_log(text, "error") raise Exception(text) if stake > account.balance: text = "Don't have enough coins. stake: {stake}, account balance: {balance}".format(stake=stake, balance=account.balance) - #local.add_log(text, "error") + # self.local.add_log(text, "error") raise Exception(text) #end if @@ -1529,7 +1296,7 @@ def GetStake(self, account, args=None): def GetMaxFactor(self): # Either use defined maxFactor, or set maximal allowed by config17 - maxFactor = local.db.get("maxFactor") + maxFactor = self.local.db.get("maxFactor") if maxFactor is None: config17 = self.GetConfig17() maxFactor = config17["maxStakeFactor"] / 65536 @@ -1537,15 +1304,53 @@ def GetMaxFactor(self): return maxFactor #end define + def GetNominationControllerLastSentStakeTime(self, addrB64): + cmd = f"runmethodfull {addrB64} all_data" + result = self.liteClient.Run(cmd) + buff = self.Result2List(result) + return buff[-1] + #end define + + def IsNominationControllerReadyToStake(self, addrB64): + now = GetTimestamp() + config15 = self.GetConfig15() + lastSentStakeTime = self.GetNominationControllerLastSentStakeTime(addrB64) + stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] + result = lastSentStakeTime + stakeFreezeDelay < now + return result + #end define + + def IsNominationControllerReadyToVote(self, addrB64): + vwl = self.GetValidatorsWalletsList() + result = addrB64 in vwl + return result + #end define + + def GetNominationController(self, mode): + self.local.AddLog("start GetNominationController function", "debug") + nominationControllerList = ["nomination_controller_001", "nomination_controller_002"] + for item in nominationControllerList: + wallet = self.GetLocalWallet(item) + if mode == "stake" and self.IsNominationControllerReadyToStake(wallet.addrB64): + return wallet + if mode == "vote" and self.IsNominationControllerReadyToVote(wallet.addrB64): + return wallet + raise Exception("Validator сontroller not found") + #end define + def GetValidatorWallet(self, mode="stake"): - local.add_log("start GetValidatorWallet function", "debug") - walletName = local.db.get("validatorWalletName") - wallet = self.GetLocalWallet(walletName) + self.local.add_log("start GetValidatorWallet function", "debug") + useNominationController = self.local.db.get("useNominationController") + if useNominationController is True: + wallet = self.GetNominationController(mode) + else: + walletName = self.local.db.get("validatorWalletName") + wallet = self.GetLocalWallet(walletName) return wallet #end define def ElectionEntry(self, args=None): - usePool = local.db.get("usePool") + usePool = self.local.db.get("usePool") wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 if wallet is None: @@ -1557,12 +1362,12 @@ def ElectionEntry(self, args=None): addrB64 = pool.addrB64 #end if - local.add_log("start ElectionEntry function", "debug") + self.local.add_log("start ElectionEntry function", "debug") # Check if validator is not synchronized validatorStatus = self.GetValidatorStatus() validatorOutOfSync = validatorStatus.get("outOfSync") if validatorOutOfSync > 60: - local.add_log("Validator is not synchronized", "error") + self.local.add_log("Validator is not synchronized", "error") return #end if @@ -1572,7 +1377,7 @@ def ElectionEntry(self, args=None): # Check if elections started if (startWorkTime == 0): - local.add_log("Elections have not yet begun", "info") + self.local.add_log("Elections have not yet begun", "info") return #end if @@ -1580,15 +1385,15 @@ def ElectionEntry(self, args=None): adnlAddr = self.GetAdnlAddr() # Check wether it is too early to participate - if "participateBeforeEnd" in local.db: + if "participateBeforeEnd" in self.local.db: now = time.time() - if (startWorkTime - now) > local.db["participateBeforeEnd"] and \ - (now + local.db["periods"]["elections"]) < startWorkTime: + if (startWorkTime - now) > self.local.db["participateBeforeEnd"] and \ + (now + self.local.db["periods"]["elections"]) < startWorkTime: return # Check if election entry already completed entries = self.GetElectionEntries() if adnlAddr in entries: - local.add_log("Elections entry already completed", "info") + self.local.add_log("Elections entry already completed", "info") return #end if @@ -1632,11 +1437,11 @@ def ElectionEntry(self, args=None): # Save vars to json file self.SaveElectionVarsToJsonFile(wallet=wallet, account=account, stake=stake, maxFactor=maxFactor, fullElectorAddr=fullElectorAddr, startWorkTime=startWorkTime, validatorsElectedFor=validatorsElectedFor, endWorkTime=endWorkTime, validatorKey=validatorKey, validatorPubkey_b64=validatorPubkey_b64, adnlAddr=adnlAddr, var1=var1, validatorSignature=validatorSignature, validatorPubkey=validatorPubkey) - local.add_log("ElectionEntry completed. Start work time: " + str(startWorkTime)) + self.local.add_log("ElectionEntry completed. Start work time: " + str(startWorkTime)) #end define def GetValidatorKeyByTime(self, startWorkTime, endWorkTime): - local.add_log("start GetValidatorKeyByTime function", "debug") + self.local.add_log("start GetValidatorKeyByTime function", "debug") # Check temp key vconfig = self.GetValidatorConfig() for item in vconfig.validators: @@ -1660,18 +1465,18 @@ def RecoverStake(self): raise Exception("Validator wallet not found") #end if - local.add_log("start RecoverStake function", "debug") + self.local.add_log("start RecoverStake function", "debug") fullElectorAddr = self.GetFullElectorAddr() returnedStake = self.GetReturnedStake(fullElectorAddr, wallet.addrB64) if returnedStake == 0: - local.add_log("You have nothing on the return stake", "debug") + self.local.add_log("You have nothing on the return stake", "debug") return #end if resultFilePath = self.ProcessRecoverStake() resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, fullElectorAddr, 1) self.SendFile(resultFilePath, wallet) - local.add_log("RecoverStake completed") + self.local.add_log("RecoverStake completed") #end define def PoolRecoverStake(self, poolAddr): @@ -1680,15 +1485,15 @@ def PoolRecoverStake(self, poolAddr): raise Exception("Validator wallet not found") #end if - local.add_log("start PoolRecoverStake function", "debug") + self.local.add_log("start PoolRecoverStake function", "debug") resultFilePath = self.PoolProcessRecoverStake() resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, poolAddr, 1.2) self.SendFile(resultFilePath, wallet) - local.add_log("PoolRecoverStake completed") + self.local.add_log("PoolRecoverStake completed") #end define def PoolsUpdateValidatorSet(self): - local.add_log("start PoolsUpdateValidatorSet function", "debug") + self.local.add_log("start PoolsUpdateValidatorSet function", "debug") wallet = self.GetValidatorWallet() pools = self.GetPools() for pool in pools: @@ -1696,7 +1501,7 @@ def PoolsUpdateValidatorSet(self): #end define def PoolUpdateValidatorSet(self, pool, wallet): - local.add_log("start PoolUpdateValidatorSet function", "debug") + self.local.add_log("start PoolUpdateValidatorSet function", "debug") poolAddr = pool.addrB64 poolData = self.GetPoolData(poolAddr) if poolData is None: @@ -1727,7 +1532,7 @@ def PoolUpdateValidatorSet(self, pool, wallet): #end define def PoolProcessUpdateValidatorSet(self, poolAddr, wallet): - local.add_log("start PoolProcessUpdateValidatorSet function", "debug") + self.local.add_log("start PoolProcessUpdateValidatorSet function", "debug") resultFilePath = self.tempDir + "pool-update-validator-set-query.boc" fiftScript = self.contractsDir + "nominator-pool/func/update-validator-set.fif" args = [fiftScript, resultFilePath] @@ -1735,19 +1540,19 @@ def PoolProcessUpdateValidatorSet(self, poolAddr, wallet): resultFilePath = parse(result, "Saved to file ", '\n') resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, poolAddr, 1.1) self.SendFile(resultFilePath, wallet) - local.add_log("PoolProcessUpdateValidatorSet completed") + self.local.add_log("PoolProcessUpdateValidatorSet completed") #end define def PoolWithdrawRequests(self, pool, wallet): - local.add_log("start PoolWithdrawRequests function", "debug") + self.local.add_log("start PoolWithdrawRequests function", "debug") resultFilePath = self.PoolProcessWihtdrawRequests() resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 10) self.SendFile(resultFilePath, wallet) - local.add_log("PoolWithdrawRequests completed") + self.local.add_log("PoolWithdrawRequests completed") #end define def PoolProcessWihtdrawRequests(self): - local.add_log("start PoolProcessWihtdrawRequests function", "debug") + self.local.add_log("start PoolProcessWihtdrawRequests function", "debug") resultFilePath = self.tempDir + "pool-withdraw-requests-query.boc" fiftScript = self.contractsDir + "nominator-pool/func/process-withdraw-requests.fif" args = [fiftScript, resultFilePath] @@ -1768,7 +1573,7 @@ def HasPoolWithdrawRequests(self, pool): #end define def SaveElectionVarsToJsonFile(self, **kwargs): - local.add_log("start SaveElectionVarsToJsonFile function", "debug") + self.local.add_log("start SaveElectionVarsToJsonFile function", "debug") fileName = self.tempDir + self.nodeName + str(kwargs.get("startWorkTime")) + "_ElectionEntry.json" wallet = kwargs.get("wallet") account = kwargs.get("account") @@ -1783,12 +1588,12 @@ def SaveElectionVarsToJsonFile(self, **kwargs): #ned define def CreateWallet(self, name, workchain=0, version="v1", **kwargs): - local.add_log("start CreateWallet function", "debug") + self.local.add_log("start CreateWallet function", "debug") subwalletDefault = 698983191 + workchain # 0x29A9A317 + workchain subwallet = kwargs.get("subwallet", subwalletDefault) walletPath = self.walletsDir + name if os.path.isfile(walletPath + ".pk") and "v3" not in version: - local.add_log("CreateWallet error: Wallet already exists: " + name, "warning") + self.local.add_log("CreateWallet error: Wallet already exists: " + name, "warning") else: if "v1" in version: fiftScript = "new-wallet.fif" @@ -1813,10 +1618,10 @@ def CreateHighWallet(self, name, **kwargs): subwalletDefault = 698983191 + workchain # 0x29A9A317 + workchain subwallet = kwargs.get("subwallet", subwalletDefault) version = kwargs.get("version", "hv1") - local.add_log("start CreateHighWallet function", "debug") + self.local.AddLog("start CreateHighWallet function", "debug") walletPath = self.walletsDir + name if os.path.isfile(walletPath + ".pk") and os.path.isfile(walletPath + str(subwallet) + ".addr"): - local.add_log("CreateHighWallet error: Wallet already exists: " + name + str(subwallet), "warning") + self.local.AddLog("CreateHighWallet error: Wallet already exists: " + name + str(subwallet), "warning") else: args = ["new-highload-wallet.fif", workchain, subwallet, walletPath] result = self.fift.Run(args) @@ -1829,12 +1634,12 @@ def CreateHighWallet(self, name, **kwargs): #end define def ActivateWallet(self, wallet): - local.add_log("start ActivateWallet function", "debug") + self.local.add_log("start ActivateWallet function", "debug") account = self.GetAccount(wallet.addrB64) if account.status == "empty": raise Exception("ActivateWallet error: account status is empty") elif account.status == "active": - local.add_log("ActivateWallet warning: account status is active", "warning") + self.local.add_log("ActivateWallet warning: account status is active", "warning") else: self.SendFile(wallet.bocFilePath, wallet, remove=False) #end define @@ -1870,7 +1675,7 @@ def ExportWallet(self, walletName): #end define def GetWalletsNameList(self): - local.add_log("start GetWalletsNameList function", "debug") + self.local.add_log("start GetWalletsNameList function", "debug") walletsNameList = list() for fileName in os.listdir(self.walletsDir): if fileName.endswith(".addr"): @@ -1883,7 +1688,7 @@ def GetWalletsNameList(self): #end define def GetWallets(self): - local.add_log("start GetWallets function", "debug") + self.local.add_log("start GetWallets function", "debug") wallets = list() walletsNameList = self.GetWalletsNameList() for walletName in walletsNameList: @@ -1893,7 +1698,7 @@ def GetWallets(self): #end define def GenerateWalletName(self): - local.add_log("start GenerateWalletName function", "debug") + self.local.add_log("start GenerateWalletName function", "debug") index = 1 index_str = str(index).rjust(3, '0') walletPrefix = "wallet_" @@ -1915,7 +1720,7 @@ def GenerateWalletName(self): #end define def WalletsCheck(self): - local.add_log("start WalletsCheck function", "debug") + self.local.add_log("start WalletsCheck function", "debug") wallets = self.GetWallets() for wallet in wallets: if os.path.isfile(wallet.bocFilePath): @@ -1925,7 +1730,7 @@ def WalletsCheck(self): #end define def GetValidatorConfig(self): - #local.add_log("start GetValidatorConfig function", "debug") + #self.local.add_log("start GetValidatorConfig function", "debug") result = self.validatorConsole.Run("getconfig") text = parse(result, "---------", "--------") vconfig = json.loads(text) @@ -1933,8 +1738,8 @@ def GetValidatorConfig(self): #end define def GetOverlaysStats(self): - local.add_log("start GetOverlaysStats function", "debug") - resultFilePath = local.buffer.my_temp_dir + "getoverlaysstats.json" + self.local.add_log("start GetOverlaysStats function", "debug") + resultFilePath = self.local.buffer.my_temp_dir + "getoverlaysstats.json" result = self.validatorConsole.Run(f"getoverlaysstatsjson {resultFilePath}") if "wrote stats" not in result: raise Exception(f"GetOverlaysStats error: {result}") @@ -1958,7 +1763,7 @@ def GetWalletId(self, wallet): #end define def MoveCoins(self, wallet, dest, coins, **kwargs): - local.add_log("start MoveCoins function", "debug") + self.local.add_log("start MoveCoins function", "debug") flags = kwargs.get("flags", list()) timeout = kwargs.get("timeout", 30) subwallet = kwargs.get("subwallet") @@ -1989,13 +1794,13 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): if bounceable == False and destAccount.status == "active": flags += ["-b"] text = "Find non-bounceable flag, but destination account already active. Using bounceable flag" - local.add_log(text, "warning") + self.local.add_log(text, "warning") elif "-n" not in flags and bounceable == True and destAccount.status != "active": raise Exception("Find bounceable flag, but destination account is not active. Use non-bounceable address or flag -n") #end if seqno = self.GetSeqno(wallet) - resultFilePath = local.buffer.my_temp_dir + wallet.name + "_wallet-query" + resultFilePath = self.local.buffer.my_temp_dir + wallet.name + "_wallet-query" if "v1" in wallet.version: fiftScript = "wallet.fif" args = [fiftScript, wallet.path, dest, seqno, coins, "-m", mode, resultFilePath] @@ -2013,7 +1818,7 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): #end define def MoveCoinsThroughProxy(self, wallet, dest, coins): - local.add_log("start MoveCoinsThroughProxy function", "debug") + self.local.add_log("start MoveCoinsThroughProxy function", "debug") wallet1 = self.CreateWallet("proxy_wallet1", 0) wallet2 = self.CreateWallet("proxy_wallet2", 0) self.MoveCoins(wallet, wallet1.addrB64_init, coins) @@ -2026,16 +1831,16 @@ def MoveCoinsThroughProxy(self, wallet, dest, coins): #end define def MoveCoinsFromHW(self, wallet, destList, **kwargs): - local.add_log("start MoveCoinsFromHW function", "debug") + self.local.add_log("start MoveCoinsFromHW function", "debug") flags = kwargs.get("flags") timeout = kwargs.get("timeout", 30) if len(destList) == 0: - local.add_log("MoveCoinsFromHW warning: destList is empty, break function", "warning") + self.local.add_log("MoveCoinsFromHW warning: destList is empty, break function", "warning") return #end if - orderFilePath = local.buffer.my_temp_dir + wallet.name + "_order.txt" + orderFilePath = self.local.buffer.my_temp_dir + wallet.name + "_order.txt" lines = list() for dest, coins in destList: lines.append("SEND {dest} {coins}".format(dest=dest, coins=coins)) @@ -2049,7 +1854,7 @@ def MoveCoinsFromHW(self, wallet, destList, **kwargs): elif "v2" in wallet.version: fiftScript = "highload-wallet-v2.fif" seqno = self.GetSeqno(wallet) - resultFilePath = local.buffer.my_temp_dir + wallet.name + "_wallet-query" + resultFilePath = self.local.buffer.my_temp_dir + wallet.name + "_wallet-query" args = [fiftScript, wallet.path, wallet.subwallet, seqno, orderFilePath, resultFilePath] if flags: args += flags @@ -2060,7 +1865,7 @@ def MoveCoinsFromHW(self, wallet, destList, **kwargs): def GetValidatorKey(self): vconfig = self.GetValidatorConfig() - for validator in vconfig.validators: + for validator in vconfig["validators"]: validatorId = validator["id"] key_bytes = base64.b64decode(validatorId) validatorKey = key_bytes.hex().upper() @@ -2098,7 +1903,7 @@ def GetElectionEntries(self, past=False): #end if # Get raw data - local.add_log("start GetElectionEntries function", "debug") + self.local.add_log("start GetElectionEntries function", "debug") cmd = "runmethodfull {fullElectorAddr} participant_list_extended".format(fullElectorAddr=fullElectorAddr) result = self.liteClient.Run(cmd) rawElectionEntries = self.Result2List(result) @@ -2140,10 +1945,10 @@ def GetElectionEntries(self, past=False): def GetSaveElections(self): timestamp = get_timestamp() - saveElections = local.db.get("saveElections") + saveElections = self.local.db.get("saveElections") if saveElections is None: saveElections = dict() - local.db["saveElections"] = saveElections + self.local.db["saveElections"] = saveElections buff = saveElections.copy() for key, item in buff.items(): diffTime = timestamp - int(key) @@ -2160,7 +1965,7 @@ def GetSaveElectionEntries(self, electionId): #end define def GetOffers(self): - local.add_log("start GetOffers function", "debug") + self.local.add_log("start GetOffers function", "debug") fullConfigAddr = self.GetFullConfigAddr() # Get raw data cmd = "runmethodfull {fullConfigAddr} list_proposals".format(fullConfigAddr=fullConfigAddr) @@ -2212,7 +2017,7 @@ def GetOffers(self): #end define def GetOfferDiff(self, offerHash): - local.add_log("start GetOfferDiff function", "debug") + self.local.add_log("start GetOfferDiff function", "debug") offer = self.GetOffer(offerHash) configId = offer["config"]["id"] configValue = offer["config"]["value"] @@ -2309,7 +2114,7 @@ def GetComplaints(self, electionId=None, past=False): #end if # Get raw data - local.add_log("start GetComplaints function", "debug") + self.local.add_log("start GetComplaints function", "debug") cmd = "runmethodfull {fullElectorAddr} list_complaints {electionId}".format(fullElectorAddr=fullElectorAddr, electionId=electionId) result = self.liteClient.Run(cmd) rawComplaints = self.Result2List(result) @@ -2377,10 +2182,10 @@ def GetComplaints(self, electionId=None, past=False): def GetSaveComplaints(self): timestamp = get_timestamp() - saveComplaints = local.db.get("saveComplaints") + saveComplaints = self.local.db.get("saveComplaints") if type(saveComplaints) is not dict: saveComplaints = dict() - local.db["saveComplaints"] = saveComplaints + self.local.db["saveComplaints"] = saveComplaints buff = saveComplaints.copy() for key, item in buff.items(): diffTime = timestamp - int(key) @@ -2400,7 +2205,7 @@ def GetAdnlFromPubkey(self, inputPubkey): #end define def GetComplaintsNumber(self): - local.add_log("start GetComplaintsNumber function", "debug") + self.local.add_log("start GetComplaintsNumber function", "debug") result = dict() complaints = self.GetComplaints() votedComplaints = self.GetVotedComplaints() @@ -2418,7 +2223,7 @@ def GetComplaintsNumber(self): #end define def GetComplaint(self, electionId, complaintHash): - local.add_log("start GetComplaint function", "debug") + self.local.add_log("start GetComplaint function", "debug") complaints = self.GetComplaints(electionId) for key, item in complaints.items(): if complaintHash == item.get("hash"): @@ -2427,7 +2232,7 @@ def GetComplaint(self, electionId, complaintHash): #end define def SignProposalVoteRequestWithValidator(self, offerHash, validatorIndex, validatorPubkey_b64, validatorSignature): - local.add_log("start SignProposalVoteRequestWithValidator function", "debug") + self.local.add_log("start SignProposalVoteRequestWithValidator function", "debug") fileName = self.tempDir + self.nodeName + "proposal_vote-msg-body.boc" args = ["config-proposal-vote-signed.fif", "-i", validatorIndex, offerHash, validatorPubkey_b64, validatorSignature, fileName] result = self.fift.Run(args) @@ -2436,7 +2241,7 @@ def SignProposalVoteRequestWithValidator(self, offerHash, validatorIndex, valida #end define def SignComplaintVoteRequestWithValidator(self, complaintHash, electionId, validatorIndex, validatorPubkey_b64, validatorSignature): - local.add_log("start SignComplaintRequestWithValidator function", "debug") + self.local.add_log("start SignComplaintRequestWithValidator function", "debug") fileName = self.tempDir + "complaint_vote-msg-body.boc" args = ["complaint-vote-signed.fif", validatorIndex, electionId, complaintHash, validatorPubkey_b64, validatorSignature, fileName] result = self.fift.Run(args) @@ -2445,7 +2250,7 @@ def SignComplaintVoteRequestWithValidator(self, complaintHash, electionId, valid #end define def VoteOffer(self, offerHash): - local.add_log("start VoteOffer function", "debug") + self.local.add_log("start VoteOffer function", "debug") fullConfigAddr = self.GetFullConfigAddr() wallet = self.GetValidatorWallet(mode="vote") validatorKey = self.GetValidatorKey() @@ -2453,7 +2258,7 @@ def VoteOffer(self, offerHash): validatorIndex = self.GetValidatorIndex() offer = self.GetOffer(offerHash) if validatorIndex in offer.get("votedValidators"): - local.add_log("Proposal already has been voted", "debug") + self.local.add_log("Proposal already has been voted", "debug") return var1 = self.CreateConfigProposalRequest(offerHash, validatorIndex) validatorSignature = self.GetValidatorSignature(validatorKey, var1) @@ -2464,7 +2269,7 @@ def VoteOffer(self, offerHash): #end define def VoteComplaint(self, electionId, complaintHash): - local.add_log("start VoteComplaint function", "debug") + self.local.add_log("start VoteComplaint function", "debug") complaintHash = int(complaintHash) fullElectorAddr = self.GetFullElectorAddr() wallet = self.GetValidatorWallet(mode="vote") @@ -2475,7 +2280,7 @@ def VoteComplaint(self, electionId, complaintHash): votedValidators = complaint.get("votedValidators") pubkey = complaint.get("pubkey") if validatorIndex in votedValidators: - local.add_log("Complaint already has been voted", "info") + self.local.add_log("Complaint already has been voted", "info") return var1 = self.CreateComplaintRequest(electionId, complaintHash, validatorIndex) validatorSignature = self.GetValidatorSignature(validatorKey, var1) @@ -2486,7 +2291,7 @@ def VoteComplaint(self, electionId, complaintHash): #end define def SaveComplaints(self, electionId): - local.add_log("start SaveComplaints function", "debug") + self.local.add_log("start SaveComplaints function", "debug") filePrefix = self.tempDir + "scheck_" cmd = "savecomplaints {electionId} {filePrefix}".format(electionId=electionId, filePrefix=filePrefix) result = self.liteClient.Run(cmd) @@ -2506,7 +2311,7 @@ def SaveComplaints(self, electionId): #end define def CheckComplaint(self, filePath): - local.add_log("start CheckComplaint function", "debug") + self.local.add_log("start CheckComplaint function", "debug") cmd = "loadproofcheck {filePath}".format(filePath=filePath) result = self.liteClient.Run(cmd, timeout=30) lines = result.split('\n') @@ -2542,7 +2347,7 @@ def GetValidatorsLoad(self, start, end, saveCompFiles=False): #end if text = "start GetValidatorsLoad function ({}, {})".format(start, end) - local.add_log(text, "debug") + self.local.add_log(text, "debug") if saveCompFiles is True: filePrefix = self.tempDir + f"checkload_{start}_{end}" else: @@ -2655,7 +2460,7 @@ def GetValidatorsList(self, past=False): #end define def CheckValidators(self, start, end): - local.add_log("start CheckValidators function", "debug") + self.local.add_log("start CheckValidators function", "debug") electionId = start complaints = self.GetComplaints(electionId) data = self.GetValidatorsLoad(start, end, saveCompFiles=True) @@ -2682,11 +2487,11 @@ def CheckValidators(self, start, end): fileName = self.PrepareComplaint(electionId, fileName) fileName = self.SignBocWithWallet(wallet, fileName, fullElectorAddr, 300) self.SendFile(fileName, wallet) - local.add_log("var1: {}, var2: {}, pubkey: {}, election_id: {}".format(var1, var2, pubkey, electionId), "debug") + self.local.add_log("var1: {}, var2: {}, pubkey: {}, election_id: {}".format(var1, var2, pubkey, electionId), "debug") #end define def GetOffer(self, offerHash): - local.add_log("start GetOffer function", "debug") + self.local.add_log("start GetOffer function", "debug") offers = self.GetOffers() for offer in offers: if offerHash == offer.get("hash"): @@ -2695,7 +2500,7 @@ def GetOffer(self, offerHash): #end define def GetOffersNumber(self): - local.add_log("start GetOffersNumber function", "debug") + self.local.add_log("start GetOffersNumber function", "debug") result = dict() offers = self.GetOffers() saveOffers = self.GetSaveOffers() @@ -2721,12 +2526,12 @@ def GetValidatorIndex(self, adnlAddr=None): if adnlAddr == searchAdnlAddr: return index index += 1 - local.add_log("GetValidatorIndex warning: index not found.", "warning") + self.local.add_log("GetValidatorIndex warning: index not found.", "warning") return -1 #end define def GetValidatorEfficiency(self, adnlAddr=None): - local.add_log("start GetValidatorEfficiency function", "debug") + self.local.add_log("start GetValidatorEfficiency function", "debug") validators = self.GetValidatorsList() if adnlAddr is None: adnlAddr = self.GetAdnlAddr() @@ -2735,7 +2540,7 @@ def GetValidatorEfficiency(self, adnlAddr=None): if adnlAddr == searchAdnlAddr: efficiency = validator.get("efficiency") return efficiency - local.add_log("GetValidatorEfficiency warning: efficiency not found.", "warning") + self.local.add_log("GetValidatorEfficiency warning: efficiency not found.", "warning") #end define def GetDbUsage(self): @@ -2745,7 +2550,7 @@ def GetDbUsage(self): #end define def GetDbSize(self, exceptions="log"): - local.add_log("start GetDbSize function", "debug") + self.local.add_log("start GetDbSize function", "debug") exceptions = exceptions.split() totalSize = 0 path = "/var/ton-work/" @@ -2906,8 +2711,18 @@ def GetDomainFromAuction(self, walletName, addr): self.SendFile(resultFilePath, wallet) #end define + def GetDomainFromAuction(self, walletName, addr): + wallet = self.GetLocalWallet(walletName) + bocPath = self.local.buffer.my_temp_dir + "get_dns_data.boc" + bocData = bytes.fromhex("b5ee9c7241010101000e0000182fcb26a20000000000000000f36cae4d") + with open(bocPath, 'wb') as file: + file.write(bocData) + resultFilePath = self.SignBocWithWallet(wallet, bocPath, addr, 0.1) + self.SendFile(resultFilePath, wallet) + #end define + def NewDomain(self, domain): - local.add_log("start NewDomain function", "debug") + self.local.add_log("start NewDomain function", "debug") domainName = domain["name"] buff = domainName.split('.') subdomain = buff.pop(0) @@ -2933,15 +2748,15 @@ def NewDomain(self, domain): #end define def AddDomain(self, domain): - if "domains" not in local.db: - local.db["domains"] = list() + if "domains" not in self.local.db: + self.local.db["domains"] = list() #end if - local.db["domains"].append(domain) - local.save() + self.local.db["domains"].append(domain) + self.local.save() #end define def GetDomains(self): - domains = local.db.get("domains", list()) + domains = self.local.db.get("domains", list()) for domain in domains: domainName = domain.get("name") domain["endTime"] = self.GetDomainEndTime(domainName) @@ -2957,39 +2772,39 @@ def GetDomain(self, domainName): #end define def DeleteDomain(self, domainName): - domains = local.db.get("domains") + domains = self.local.db.get("domains") for domain in domains: if (domainName == domain.get("name")): domains.remove(domain) - local.save() + self.local.save() return raise Exception("DeleteDomain error: Domain not found") #end define def GetAutoTransferRules(self): - autoTransferRules = local.db.get("autoTransferRules") + autoTransferRules = self.local.db.get("autoTransferRules") if autoTransferRules is None: autoTransferRules = list() - local.db["autoTransferRules"] = autoTransferRules + self.local.db["autoTransferRules"] = autoTransferRules return autoTransferRules #end define def AddAutoTransferRule(self, rule): autoTransferRules = self.GetAutoTransferRules() autoTransferRules.append(rule) - local.save() + self.local.save() #end define def AddBookmark(self, bookmark): - if "bookmarks" not in local.db: - local.db["bookmarks"] = list() + if "bookmarks" not in self.local.db: + self.local.db["bookmarks"] = list() #end if - local.db["bookmarks"].append(bookmark) - local.save() + self.local.db["bookmarks"].append(bookmark) + self.local.save() #end define def GetBookmarks(self): - bookmarks = local.db.get("bookmarks") + bookmarks = self.local.db.get("bookmarks") if bookmarks is not None: for bookmark in bookmarks: self.WriteBookmarkData(bookmark) @@ -2997,7 +2812,7 @@ def GetBookmarks(self): #end define def GetBookmarkAddr(self, type, name): - bookmarks = local.db.get("bookmarks", list()) + bookmarks = self.local.db.get("bookmarks", list()) for bookmark in bookmarks: bookmarkType = bookmark.get("type") bookmarkName = bookmark.get("name") @@ -3008,13 +2823,13 @@ def GetBookmarkAddr(self, type, name): #end define def DeleteBookmark(self, name, type): - bookmarks = local.db.get("bookmarks") + bookmarks = self.local.db.get("bookmarks") for bookmark in bookmarks: bookmarkType = bookmark.get("type") bookmarkName = bookmark.get("name") if (type == bookmarkType and name == bookmarkName): bookmarks.remove(bookmark) - local.save() + self.local.save() return raise Exception("DeleteBookmark error: Bookmark not found") #end define @@ -3042,10 +2857,10 @@ def WriteBookmarkData(self, bookmark): def GetSaveOffers(self): bname = "saveOffers" - saveOffers = local.db.get(bname) - if type(saveOffers) != dict: - saveOffers = dict() - local.db[bname] = saveOffers + saveOffers = self.local.db.get(bname) + if saveOffers is None: + saveOffers = list() + self.local.db[bname] = saveOffers return saveOffers #end define @@ -3054,16 +2869,16 @@ def AddSaveOffer(self, offer): offerPseudohash = offer.get("pseudohash") saveOffers = self.GetSaveOffers() if offerHash not in saveOffers: - saveOffers[offerHash] = offerPseudohash - local.save() + saveOffers.append(offerHash) + self.local.save() #end define def GetVotedComplaints(self): bname = "votedComplaints" - votedComplaints = local.db.get(bname) + votedComplaints = self.local.db.get(bname) if votedComplaints is None: votedComplaints = dict() - local.db[bname] = votedComplaints + self.local.db[bname] = votedComplaints return votedComplaints #end define @@ -3072,7 +2887,7 @@ def AddVotedComplaints(self, complaint): votedComplaints = self.GetVotedComplaints() if pseudohash not in votedComplaints: votedComplaints[pseudohash] = complaint - local.save() + self.local.save() #end define def GetDestinationAddr(self, destination): @@ -3138,7 +2953,7 @@ def ParseAddrB64(self, addrB64): networkTestnet = self.IsTestnet() if testnet != networkTestnet: text = f"ParseAddrB64 warning: testnet flag do not match. Addr: {testnet}, Network: {networkTestnet}" - local.add_log(text, "warning") + self.local.add_log(text, "warning") #end if # get wc and addr @@ -3147,7 +2962,8 @@ def ParseAddrB64(self, addrB64): crc_bytes = b[34:36] crc_data = bytes(b[:34]) crc = int.from_bytes(crc_bytes, "big") - check_crc = crc16.xmodem(crc_data) + # check_crc = crc16.crc16xmodem(crc_data) + check_crc = fastcrc.crc16.xmodem(crc_data) # TODO: check this library! if crc != check_crc: raise Exception("ParseAddrB64 error: crc do not match") #end if @@ -3192,7 +3008,7 @@ def IsBounceableAddrB64(self, inputAddr): def GetNetLoadAvg(self, statistics=None): if statistics is None: - statistics = local.db.get("statistics") + statistics = self.local.db.get("statistics") if statistics: netLoadAvg = statistics.get("netLoadAvg") else: @@ -3202,7 +3018,7 @@ def GetNetLoadAvg(self, statistics=None): def GetTpsAvg(self, statistics=None): if statistics is None: - statistics = local.db.get("statistics") + statistics = self.local.db.get("statistics") if statistics: tpsAvg = statistics.get("tpsAvg") else: @@ -3212,7 +3028,7 @@ def GetTpsAvg(self, statistics=None): def GetStatistics(self, name, statistics=None): if statistics is None: - statistics = local.db.get("statistics") + statistics = self.local.db.get("statistics") if statistics: data = statistics.get(name) else: @@ -3221,8 +3037,8 @@ def GetStatistics(self, name, statistics=None): #end define def GetSettings(self, name): - #local.load_db() - result = local.db.get(name) + # self.local.load_db() + result = self.local.db.get(name) return result #end define @@ -3230,8 +3046,8 @@ def SetSettings(self, name, data): try: data = json.loads(data) except: pass - local.db[name] = data - local.save() + self.local.db[name] = data + self.local.save() #end define def Tlb2Json(self, text): @@ -3305,7 +3121,7 @@ def Tlb2Json(self, text): #end define def SignShardOverlayCert(self, adnl, pubkey): - local.add_log("start SignShardOverlayCert function", "debug") + self.local.add_log("start SignShardOverlayCert function", "debug") fileName = self.tempDir + pubkey + ".cert" cmd = "signshardoverlaycert {workchain} {shardprefix} {pubkey} {expireat} {maxsize} {outfile}" cmd = cmd.format(workchain=-1, shardprefix=-9223372036854775808, pubkey=pubkey, expireat=172800, maxsize=8192, outfile=fileName) @@ -3327,7 +3143,7 @@ def SignShardOverlayCert(self, adnl, pubkey): #end define def ImportShardOverlayCert(self): - local.add_log("start ImportShardOverlayCert function", "debug") + self.local.add_log("start ImportShardOverlayCert function", "debug") adnlAddr = self.GetAdnlAddr() pubkey = self.GetPubKey(adnlAddr) adnl = pubkey # adnl = adnlAddr @@ -3352,7 +3168,7 @@ def ImportShardOverlayCert(self): # Check certificate if cert is None: - local.add_log("ImportShardOverlayCert warning: certificate not found", "warning") + self.local.add_log("ImportShardOverlayCert warning: certificate not found", "warning") return #end if @@ -3364,7 +3180,7 @@ def ImportShardOverlayCert(self): #end define def ImportCertificate(self, pubkey, fileName): - local.add_log("start ImportCertificate function", "debug") + self.local.add_log("start ImportCertificate function", "debug") cmd = "importshardoverlaycert {workchain} {shardprefix} {pubkey} {certfile}" cmd = cmd.format(workchain=-1, shardprefix=-9223372036854775808, pubkey=pubkey, certfile=fileName) result = self.validatorConsole.Run(cmd) @@ -3380,7 +3196,7 @@ def GetValidatorsWalletsList(self): #end define def DownloadContract(self, url, branch=None): - local.add_log("start DownloadContract function", "debug") + self.local.add_log("start DownloadContract function", "debug") buff = url.split('/') gitPath = self.contractsDir + buff[-1] + '/' @@ -3411,8 +3227,73 @@ def DownloadContract(self, url, branch=None): #end if #end define + def CreateNominationController(self, name, nominatorAddr, **kwargs): + workchain = kwargs.get("workchain", -1) + subwalletDefault = 698983191 + workchain # 0x29A9A317 + workchain + subwallet = kwargs.get("subwallet", subwalletDefault) + rewardShare = kwargs.get("rewardShare", 0) + coverAbility = kwargs.get("coverAbility", 0) + self.local.AddLog("start CreateNominationController function", "debug") + walletPath = self.walletsDir + name + contractPath = self.contractsDir + "nomination-contract/" + if not os.path.isdir(contractPath): + self.DownloadContract("https://github.com/EmelyanenkoK/nomination-contract") + #end if + + fiftScript = contractPath + "scripts/new-nomination-controller.fif" + args = [fiftScript, workchain, subwallet, nominatorAddr, rewardShare, coverAbility, walletPath] + result = self.fift.Run(args) + version = "v3r3" + wallet = self.GetLocalWallet(name, version) + self.SetWalletVersion(wallet.addrB64, version) + #end define + + def DepositToNominationController(self, walletName, destAddr, amount): + wallet = self.GetLocalWallet(walletName) + bocPath = self.contractsDir + "nomination-contract/scripts/add-stake.boc" + resultFilePath = self.SignBocWithWallet(wallet, bocPath, destAddr, amount) + self.SendFile(resultFilePath, wallet) + #end define + + def WithdrawFromNominationController(self, walletName, destAddr, amount): + wallet = self.GetLocalWallet(walletName) + fiftScript = self.contractsDir + "nomination-contract/scripts/request-stake.fif" # withdraw-stake.fif + bocPath = self.contractsDir + "nomination-contract/scripts/withdraw-stake" + args = [fiftScript, amount, bocPath] + result = self.fift.Run(args) + bocPath = parse(result, "Saved to file ", ")") + resultFilePath = self.SignBocWithWallet(wallet, bocPath, destAddr, 1) + self.SendFile(resultFilePath, wallet) + #end define + + def SendRequestToNominationController(self, walletName, destAddr): + wallet = self.GetLocalWallet(walletName) + bocPath = self.contractsDir + "nomination-contract/scripts/elector-refund.boc" + resultFilePath = self.SignBocWithWallet(wallet, bocPath, destAddr, 1.5) + self.SendFile(resultFilePath, wallet) + #end define + + def CreateRestrictedWallet(self, name, ownerAddr, **kwargs): + workchain = kwargs.get("workchain", 0) + subwalletDefault = 698983191 + workchain # 0x29A9A317 + workchain + subwallet = kwargs.get("subwallet", subwalletDefault) + self.local.AddLog("start CreateRestrictedWallet function", "debug") + walletPath = self.walletsDir + name + contractPath = self.contractsDir + "nomination-contract/" + if not os.path.isdir(contractPath): + self.DownloadContract("https://github.com/EmelyanenkoK/nomination-contract") + #end if + + fiftScript = contractPath + "scripts/new-restricted-wallet.fif" + args = [fiftScript, workchain, subwallet, ownerAddr, walletPath] + result = self.fift.Run(args) + version = "v3r4" + wallet = self.GetLocalWallet(name, version) + self.SetWalletVersion(wallet.addrB64, version) + #end define + def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake): - local.add_log("start CreatePool function", "debug") + self.local.add_log("start CreatePool function", "debug") validatorRewardShare = int(validatorRewardSharePercent * 100) contractPath = self.contractsDir + "nominator-pool/" if not os.path.isdir(contractPath): @@ -3421,7 +3302,7 @@ def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, filePath = self.poolsDir + poolName if os.path.isfile(filePath + ".addr"): - local.add_log("CreatePool warning: Pool already exists: " + filePath, "warning") + self.local.add_log("CreatePool warning: Pool already exists: " + filePath, "warning") return #end if @@ -3443,7 +3324,7 @@ def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, #end define def ActivatePool(self, pool, ex=True): - local.add_log("start ActivatePool function", "debug") + self.local.add_log("start ActivatePool function", "debug") for i in range(10): time.sleep(3) account = self.GetAccount(pool.addrB64) @@ -3456,7 +3337,7 @@ def ActivatePool(self, pool, ex=True): def DepositToPool(self, walletName, poolAddr, amount): wallet = self.GetLocalWallet(walletName) - bocPath = local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" + bocPath = self.local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" fiftScript = self.contractsDir + "nominator-pool/func/validator-deposit.fif" args = [fiftScript, bocPath] result = self.fift.Run(args) @@ -3473,9 +3354,9 @@ def WithdrawFromPool(self, poolAddr, amount): #end define def WithdrawFromPoolProcess(self, poolAddr, amount): - local.add_log("start WithdrawFromPoolProcess function", "debug") - wallet = self.GetValidatorWallet() - bocPath = local.buffer.my_temp_dir + wallet.name + "validator-withdraw-query.boc" + self.local.add_log("start WithdrawFromPoolProcess function", "debug") + wallet = self.GetLocalWallet() + bocPath = self.local.buffer.my_temp_dir + wallet.name + "validator-withdraw-query.boc" fiftScript = self.contractsDir + "nominator-pool/func/validator-withdraw.fif" args = [fiftScript, amount, bocPath] result = self.fift.Run(args) @@ -3484,10 +3365,10 @@ def WithdrawFromPoolProcess(self, poolAddr, amount): #end define def PendWithdrawFromPool(self, poolAddr, amount): - local.add_log("start PendWithdrawFromPool function", "debug") + self.local.add_log("start PendWithdrawFromPool function", "debug") pendingWithdraws = self.GetPendingWithdraws() pendingWithdraws[poolAddr] = amount - local.save() + self.local.save() #end define def HandlePendingWithdraw(self, pendingWithdraws, poolAddr): @@ -3498,15 +3379,15 @@ def HandlePendingWithdraw(self, pendingWithdraws, poolAddr): def GetPendingWithdraws(self): bname = "pendingWithdraws" - pendingWithdraws = local.db.get(bname) + pendingWithdraws = self.local.db.get(bname) if pendingWithdraws is None: pendingWithdraws = dict() - local.db[bname] = pendingWithdraws + self.local.db[bname] = pendingWithdraws return pendingWithdraws #end define def SignElectionRequestWithPoolWithValidator(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): - local.add_log("start SignElectionRequestWithPoolWithValidator function", "debug") + self.local.add_log("start SignElectionRequestWithPoolWithValidator function", "debug") fileName = self.tempDir + str(startWorkTime) + "_validator-query.boc" fiftScript = self.contractsDir + "nominator-pool/func/validator-elect-signed.fif" args = [fiftScript, pool.addrB64, startWorkTime, maxFactor, adnlAddr, validatorPubkey_b64, validatorSignature, fileName, stake] @@ -3517,7 +3398,7 @@ def SignElectionRequestWithPoolWithValidator(self, pool, startWorkTime, adnlAddr #end define def PoolProcessRecoverStake(self): - local.add_log("start PoolProcessRecoverStake function", "debug") + self.local.add_log("start PoolProcessRecoverStake function", "debug") resultFilePath = self.tempDir + "recover-query.boc" fiftScript = self.contractsDir + "nominator-pool/func/recover-stake.fif" args = [fiftScript, resultFilePath] @@ -3526,8 +3407,38 @@ def PoolProcessRecoverStake(self): return resultFilePath #end define + def GetControllerData(self, addrB64): + self.local.add_log("start GetControllerData function", "debug") + account = self.GetAccount(addrB64) + if account.status != "active": + return + cmd = "runmethodfull {addrB64} all_data".format(addrB64=addrB64) + result = self.liteClient.Run(cmd) + data = self.Result2List(result) + controllerData = dict() + wallet_data = dict() + wallet_data["seqno"] = data[0][0] + wallet_data["subwallet_id"] = data[0][1] + wallet_data["controller_pubkey"] = data[0][2] + wallet_data["last_used"] = data[0][3] + static_data = dict() + static_data["nominator_address"] = data[1][0] + static_data["controller_reward_share"] = data[1][1] + static_data["controller_cover_ability"] = data[1][2] + balances = dict() + balances["nominator_total_balance"] = data[2][0] + balances["nominator_elector_balance"] = data[2][1] + balances["nominator_withdrawal_request"] = data[2][2] + balances["total_stake_on_elector"] = data[2][3] + controllerData["wallet_data"] = wallet_data + controllerData["static_data"] = static_data + controllerData["balances"] = balances + controllerData["last_sent_stake_time"] = data[3] + return controllerData + #end define + def GetLocalPool(self, poolName): - local.add_log("start GetLocalPool function", "debug") + self.local.add_log("start GetLocalPool function", "debug") if poolName is None: return None filePath = self.poolsDir + poolName @@ -3543,7 +3454,7 @@ def GetLocalPool(self, poolName): #end define def GetPoolsNameList(self): - local.add_log("start GetPoolsNameList function", "debug") + self.local.add_log("start GetPoolsNameList function", "debug") poolsNameList = list() for fileName in os.listdir(self.poolsDir): if fileName.endswith(".addr"): @@ -3554,7 +3465,7 @@ def GetPoolsNameList(self): #end define def GetPools(self): - local.add_log("start GetPools function", "debug") + self.local.add_log("start GetPools function", "debug") pools = list() poolsNameList = self.GetPoolsNameList() for poolName in poolsNameList: @@ -3595,7 +3506,7 @@ def IsPoolReadyToVote(self, addrB64): #end define def GetPoolData(self, addrB64): - local.add_log("start GetPoolData function", "debug") + self.local.add_log("start GetPoolData function", "debug") cmd = f"runmethodfull {addrB64} get_pool_data" result = self.liteClient.Run(cmd) data = self.Result2List(result) @@ -3640,7 +3551,7 @@ def GetNetworkName(self): def GetFunctionBuffer(self, name, timeout=10): timestamp = get_timestamp() - buff = local.buffer.get(name) + buff = self.local.buffer.get(name) if buff is None: return buffTime = buff.get("time") @@ -3655,7 +3566,7 @@ def SetFunctionBuffer(self, name, data): buff = dict() buff["time"] = get_timestamp() buff["data"] = data - local.buffer[name] = buff + self.local.buffer[name] = buff #end define def IsTestnet(self): @@ -3698,523 +3609,6 @@ def IsHash(self, inputHash): #end define #end class -def ng2g(ng): - if ng is None: - return - return int(ng)/10**9 -#end define - -def Init(): - # Event reaction - if ("-e" in sys.argv): - x = sys.argv.index("-e") - eventName = sys.argv[x+1] - Event(eventName) - #end if - - local.run() - - # statistics - local.buffer.blocksData = dict() - local.buffer.transData = dict() - local.buffer.network = [None]*15*6 - local.buffer.diskio = [None]*15*6 - - # scan blocks - local.buffer.masterBlocksList = list() - local.buffer.prevShardsBlock = dict() - local.buffer.blocksNum = 0 - local.buffer.transNum = 0 -#end define - -def Event(eventName): - if eventName == "enableVC": - EnableVcEvent() - elif eventName == "validator down": - ValidatorDownEvent() - local.exit() -#end define - -def EnableVcEvent(): - local.add_log("start EnableVcEvent function", "debug") - # Создать новый кошелек для валидатора - ton = MyTonCore() - wallet = ton.CreateWallet("validator_wallet_001", -1) - local.db["validatorWalletName"] = wallet.name - - # Создать новый ADNL адрес для валидатора - adnlAddr = ton.CreateNewKey() - ton.AddAdnlAddrToValidator(adnlAddr) - local.db["adnlAddr"] = adnlAddr - - # Сохранить - local.save() -#end define - -def ValidatorDownEvent(): - local.add_log("start ValidatorDownEvent function", "debug") - local.add_log("Validator is down", "error") -#end define - -def Elections(ton): - usePool = local.db.get("usePool") - if usePool == True: - ton.PoolsUpdateValidatorSet() - ton.RecoverStake() - ton.ElectionEntry() - else: - ton.RecoverStake() - ton.ElectionEntry() -#end define - -def Statistics(): - ReadNetworkData() - SaveNetworkStatistics() - #ReadTransData(scanner) - SaveTransStatistics() - ReadDiskData() - SaveDiskStatistics() -#end define - -def ReadDiskData(): - timestamp = get_timestamp() - disks = GetDisksList() - buff = psutil.disk_io_counters(perdisk=True) - data = dict() - for name in disks: - data[name] = dict() - data[name]["timestamp"] = timestamp - data[name]["busyTime"] = buff[name].busy_time - data[name]["readBytes"] = buff[name].read_bytes - data[name]["writeBytes"] = buff[name].write_bytes - data[name]["readCount"] = buff[name].read_count - data[name]["writeCount"] = buff[name].write_count - #end for - - local.buffer.diskio.pop(0) - local.buffer.diskio.append(data) -#end define - -def SaveDiskStatistics(): - data = local.buffer.diskio - data = data[::-1] - zerodata = data[0] - buff1 = data[1*6-1] - buff5 = data[5*6-1] - buff15 = data[15*6-1] - if buff5 is None: - buff5 = buff1 - if buff15 is None: - buff15 = buff5 - #end if - - disksLoadAvg = dict() - disksLoadPercentAvg = dict() - iopsAvg = dict() - disks = GetDisksList() - for name in disks: - if zerodata[name]["busyTime"] == 0: - continue - diskLoad1, diskLoadPercent1, iops1 = CalculateDiskStatistics(zerodata, buff1, name) - diskLoad5, diskLoadPercent5, iops5 = CalculateDiskStatistics(zerodata, buff5, name) - diskLoad15, diskLoadPercent15, iops15 = CalculateDiskStatistics(zerodata, buff15, name) - disksLoadAvg[name] = [diskLoad1, diskLoad5, diskLoad15] - disksLoadPercentAvg[name] = [diskLoadPercent1, diskLoadPercent5, diskLoadPercent15] - iopsAvg[name] = [iops1, iops5, iops15] - #end fore - - # save statistics - statistics = local.db.get("statistics", dict()) - statistics["disksLoadAvg"] = disksLoadAvg - statistics["disksLoadPercentAvg"] = disksLoadPercentAvg - statistics["iopsAvg"] = iopsAvg - local.db["statistics"] = statistics -#end define - -def CalculateDiskStatistics(zerodata, data, name): - if data is None: - return None, None, None - data = data[name] - zerodata = zerodata[name] - timeDiff = zerodata["timestamp"] - data["timestamp"] - busyTimeDiff = zerodata["busyTime"] - data["busyTime"] - diskReadDiff = zerodata["readBytes"] - data["readBytes"] - diskWriteDiff = zerodata["writeBytes"] - data["writeBytes"] - diskReadCountDiff = zerodata["readCount"] - data["readCount"] - diskWriteCountDiff = zerodata["writeCount"] - data["writeCount"] - diskLoadPercent = busyTimeDiff /1000 /timeDiff *100 # /1000 - to second, *100 - to percent - diskLoadPercent = round(diskLoadPercent, 2) - diskRead = diskReadDiff /timeDiff - diskWrite = diskWriteDiff /timeDiff - diskReadCount = diskReadCountDiff /timeDiff - diskWriteCount = diskWriteCountDiff /timeDiff - diskLoad = b2mb(diskRead + diskWrite) - iops = round(diskReadCount + diskWriteCount, 2) - return diskLoad, diskLoadPercent, iops -#end define - -def GetDisksList(): - data = list() - buff = os.listdir("/sys/block/") - for item in buff: - if "loop" in item: - continue - data.append(item) - #end for - data.sort() - return data -#end define - -def ReadNetworkData(): - timestamp = get_timestamp() - interfaceName = get_internet_interface_name() - buff = psutil.net_io_counters(pernic=True) - buff = buff[interfaceName] - data = dict() - data["timestamp"] = timestamp - data["bytesRecv"] = buff.bytes_recv - data["bytesSent"] = buff.bytes_sent - data["packetsSent"] = buff.packets_sent - data["packetsRecv"] = buff.packets_recv - - local.buffer.network.pop(0) - local.buffer.network.append(data) -#end define - -def SaveNetworkStatistics(): - data = local.buffer.network - data = data[::-1] - zerodata = data[0] - buff1 = data[1*6-1] - buff5 = data[5*6-1] - buff15 = data[15*6-1] - if buff5 is None: - buff5 = buff1 - if buff15 is None: - buff15 = buff5 - #end if - - netLoadAvg = dict() - ppsAvg = dict() - networkLoadAvg1, ppsAvg1 = CalculateNetworkStatistics(zerodata, buff1) - networkLoadAvg5, ppsAvg5 = CalculateNetworkStatistics(zerodata, buff5) - networkLoadAvg15, ppsAvg15 = CalculateNetworkStatistics(zerodata, buff15) - netLoadAvg = [networkLoadAvg1, networkLoadAvg5, networkLoadAvg15] - ppsAvg = [ppsAvg1, ppsAvg5, ppsAvg15] - - # save statistics - statistics = local.db.get("statistics", dict()) - statistics["netLoadAvg"] = netLoadAvg - statistics["ppsAvg"] = ppsAvg - local.db["statistics"] = statistics -#end define - -def CalculateNetworkStatistics(zerodata, data): - if data is None: - return None, None - timeDiff = zerodata["timestamp"] - data["timestamp"] - bytesRecvDiff = zerodata["bytesRecv"] - data["bytesRecv"] - bytesSentDiff = zerodata["bytesSent"] - data["bytesSent"] - packetsRecvDiff = zerodata["packetsRecv"] - data["packetsRecv"] - packetsSentDiff = zerodata["packetsSent"] - data["packetsSent"] - bitesRecvAvg = bytesRecvDiff /timeDiff *8 - bitesSentAvg = bytesSentDiff /timeDiff *8 - packetsRecvAvg = packetsRecvDiff /timeDiff - packetsSentAvg = packetsSentDiff /timeDiff - netLoadAvg = b2mb(bitesRecvAvg + bitesSentAvg) - ppsAvg = round(packetsRecvAvg + packetsSentAvg, 2) - return netLoadAvg, ppsAvg -#end define - -def ReadTransData(scanner): - transData = local.buffer.transData - SetToTimeData(transData, scanner.transNum) - ShortTimeData(transData) -#end define - -def SetToTimeData(timeDataList, data): - timenow = int(time.time()) - timeDataList[timenow] = data -#end define - -def ShortTimeData(data, max=120, diff=20): - if len(data) < max: - return - buff = data.copy() - data.clear() - keys = sorted(buff.keys(), reverse=True) - for item in keys[:max-diff]: - data[item] = buff[item] -#end define - -def SaveTransStatistics(): - tps1 = GetTps(60) - tps5 = GetTps(60*5) - tps15 = GetTps(60*15) - - # save statistics - statistics = local.db.get("statistics", dict()) - statistics["tpsAvg"] = [tps1, tps5, tps15] - local.db["statistics"] = statistics -#end define - -def GetDataPerSecond(data, timediff): - if len(data) == 0: - return - timenow = sorted(data.keys())[-1] - now = data.get(timenow) - prev = GetItemFromTimeData(data, timenow-timediff) - if prev is None: - return - diff = now - prev - result = diff / timediff - result = round(result, 2) - return result -#end define - -def GetItemFromTimeData(data, timeneed): - if timeneed in data: - result = data.get(timeneed) - else: - result = data[min(data.keys(), key=lambda k: abs(k-timeneed))] - return result -#end define - - -def GetTps(timediff): - data = local.buffer.transData - tps = GetDataPerSecond(data, timediff) - return tps -#end define - -def GetBps(timediff): - data = local.buffer.blocksData - bps = GetDataPerSecond(data, timediff) - return bps -#end define - -def GetBlockTimeAvg(timediff): - bps = GetBps(timediff) - if bps is None or bps == 0: - return - result = 1/bps - result = round(result, 2) - return result -#end define - -def Offers(ton): - saveOffers = ton.GetSaveOffers() - offers = ton.GetOffers() - for offer in offers: - offerHash = offer.get("hash") - offerPseudohash = offer.get("pseudohash") - saveOfferPseudohash = saveOffers.get(offerHash) - if offerPseudohash == saveOfferPseudohash: - ton.VoteOffer(offerHash) -#end define - -def Domains(ton): - pass -#end define - -def GetUname(): - data = os.uname() - result = dict(zip('sysname nodename release version machine'.split(), data)) - result.pop("nodename") - return result -#end define - -def GetMemoryInfo(): - result = dict() - data = psutil.virtual_memory() - result["total"] = round(data.total / 10**9, 2) - result["usage"] = round(data.used / 10**9, 2) - result["usagePercent"] = data.percent - return result -#end define - -def GetSwapInfo(): - result = dict() - data = psutil.swap_memory() - result["total"] = round(data.total / 10**9, 2) - result["usage"] = round(data.used / 10**9, 2) - result["usagePercent"] = data.percent - return result -#end define - -def GetValidatorProcessInfo(): - pid = get_service_pid("validator") - if pid == None or pid == 0: - return - p = psutil.Process(pid) - mem = p.memory_info() - result = dict() - result["cpuPercent"] = p.cpu_percent() - memory = dict() - memory["rss"] = mem.rss - memory["vms"] = mem.vms - memory["shared"] = mem.shared - memory["text"] = mem.text - memory["lib"] = mem.lib - memory["data"] = mem.data - memory["dirty"] = mem.dirty - result["memory"] = memory - #io = p.io_counters() # Permission denied: '/proc/{pid}/io' - return result -#end define - -def Telemetry(ton): - sendTelemetry = local.db.get("sendTelemetry") - if sendTelemetry is not True: - return - #end if - - # Get validator status - data = dict() - data["adnlAddr"] = ton.GetAdnlAddr() - data["validatorStatus"] = ton.GetValidatorStatus() - data["cpuNumber"] = psutil.cpu_count() - data["cpuLoad"] = get_load_avg() - data["netLoad"] = ton.GetStatistics("netLoadAvg") - data["tps"] = ton.GetStatistics("tpsAvg") - data["disksLoad"] = ton.GetStatistics("disksLoadAvg") - data["disksLoadPercent"] = ton.GetStatistics("disksLoadPercentAvg") - data["iops"] = ton.GetStatistics("iopsAvg") - data["pps"] = ton.GetStatistics("ppsAvg") - data["dbUsage"] = ton.GetDbUsage() - data["memory"] = GetMemoryInfo() - data["swap"] = GetSwapInfo() - data["uname"] = GetUname() - data["vprocess"] = GetValidatorProcessInfo() - elections = local.try_function(ton.GetElectionEntries) - complaints = local.try_function(ton.GetComplaints) - - # Get git hashes - gitHashes = dict() - gitHashes["mytonctrl"] = get_git_hash("/usr/src/mytonctrl") - gitHashes["validator"] = GetBinGitHash("/usr/bin/ton/validator-engine/validator-engine") - data["gitHashes"] = gitHashes - data["stake"] = local.db.get("stake") - - # Get validator config - vconfig = ton.GetValidatorConfig() - data["fullnode_adnl"] = vconfig.fullnode - - # Send data to toncenter server - liteUrl_default = "https://telemetry.toncenter.com/report_status" - liteUrl = local.db.get("telemetryLiteUrl", liteUrl_default) - output = json.dumps(data) - resp = requests.post(liteUrl, data=output, timeout=3) -#end define - -def GetBinGitHash(path, short=False): - if not os.path.isfile(path): - return - args = [path, "--version"] - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) - output = process.stdout.decode("utf-8") - if "build information" not in output: - return - buff = output.split(' ') - start = buff.index("Commit:") + 1 - result = buff[start].replace(',', '') - if short is True: - result = result[:7] - return result -#end define - -def OverlayTelemetry(ton): - sendTelemetry = local.db.get("sendTelemetry") - if sendTelemetry is not True: - return - #end if - - # Get validator status - data = dict() - data["adnlAddr"] = ton.GetAdnlAddr() - data["overlaysStats"] = ton.GetOverlaysStats() - - # Send data to toncenter server - overlayUrl_default = "https://telemetry.toncenter.com/report_overlays" - overlayUrl = local.db.get("overlayTelemetryUrl", overlayUrl_default) - output = json.dumps(data) - resp = requests.post(overlayUrl, data=output, timeout=3) -#end define - -def Complaints(ton): - validatorIndex = ton.GetValidatorIndex() - if validatorIndex < 0: - return - #end if - - # Voting for complaints - config32 = ton.GetConfig32() - electionId = config32.get("startWorkTime") - complaintsHashes = ton.SaveComplaints(electionId) - complaints = ton.GetComplaints(electionId) - for key, item in complaints.items(): - complaintHash = item.get("hash") - complaintHash_hex = Dec2HexAddr(complaintHash) - if complaintHash_hex in complaintsHashes: - ton.VoteComplaint(electionId, complaintHash) -#end define - -def Slashing(ton): - isSlashing = local.db.get("isSlashing") - if isSlashing is not True: - return - #end if - - # Creating complaints - slash_time = local.buffer.slash_time - config32 = ton.GetConfig32() - start = config32.get("startWorkTime") - end = config32.get("endWorkTime") - local.add_log("slash_time {}, start {}, end {}".format(slash_time, start, end), "debug") - if slash_time != start: - end -= 60 - ton.CheckValidators(start, end) - local.buffer.slash_time = start -#end define - -def ScanLiteServers(ton): - # Считать список серверов - filePath = ton.liteClient.configPath - file = open(filePath, 'rt') - text = file.read() - file.close() - data = json.loads(text) - - # Пройтись по серверам - result = list() - liteservers = data.get("liteservers") - for index in range(len(liteservers)): - try: - ton.liteClient.Run("last", index=index) - result.append(index) - except: pass - #end for - - # Записать данные в базу - local.db["liteServers"] = result -#end define - -def General(): - local.add_log("start General function", "debug") - ton = MyTonCore() - - # Запустить потоки - local.start_cycle(Elections, sec=600, args=(ton, )) - local.start_cycle(Statistics, sec=10) - local.start_cycle(Offers, sec=600, args=(ton, )) - local.start_cycle(Complaints, sec=600, args=(ton, )) - local.start_cycle(Slashing, sec=600, args=(ton, )) - local.start_cycle(Domains, sec=600, args=(ton, )) - local.start_cycle(Telemetry, sec=60, args=(ton, )) - local.start_cycle(OverlayTelemetry, sec=7200, args=(ton, )) - local.start_cycle(ScanLiteServers, sec=60, args=(ton,)) - thr_sleep() -#end define def Dec2HexAddr(dec): h = dec2hex(dec) @@ -4222,31 +3616,3 @@ def Dec2HexAddr(dec): h64 = hu.rjust(64, "0") return h64 #end define - -def xhex2hex(x): - try: - b = x[1:] - h = b.lower() - return h - except: - return None -#end define - -def hex2base64(h): - b = bytes.fromhex(h) - b64 = base64.b64encode(b) - s = b64.decode("utf-8") - return s -#end define - - - - -### -### Start of the program -### - -if __name__ == "__main__": - Init() - General() -#end if diff --git a/mytoncore/tonblocksscanner.py b/mytoncore/tonblocksscanner.py new file mode 100644 index 00000000..6f607789 --- /dev/null +++ b/mytoncore/tonblocksscanner.py @@ -0,0 +1,208 @@ +import threading +import time + +from mytoncore.models import Block + + +class TonBlocksScanner(): + def __init__(self, ton, **kwargs): + self.ton = ton + self.prevMasterBlock = None + self.prevShardsBlock = dict() + self.blocksNum = 0 + self.transNum = 0 + self.nbr = kwargs.get("nbr") #NewBlockReaction + self.ntr = kwargs.get("ntr") #NewTransReaction + self.nmr = kwargs.get("nmr") #NewMessageReaction + self.local = kwargs.get("local") + self.sync = kwargs.get("sync", False) + self.delay = 0 + self.working = False + self.closing = False + #end define + + def Run(self): + self.StartThread(self.ScanBlocks, args=()) + self.StartThread(self.ThreadBalancing, args=()) + self.StartThread(self.StatusReading, args=()) + #end define + + def StartThread(self, func, args): + threading.Thread(target=func, args=args, name=func.__name__, daemon=True).start() + #end define + + def StartWithMode(self, func, args): + if self.sync: + func(*args) + else: + self.StartThread(func, args) + #end define + + def AddLog(self, text, type): + if self.local: + self.local.AddLog(text, type) + else: + print(text) + #end define + + def Try(self, func, **kwargs): + args = kwargs.get("args", tuple()) + for step in range(10): + time.sleep(step) + try: + result = func(*args) + return result + except Exception as ex: + err = ex + text = f"{func.__name__} step: {step}, error: {err}" + self.AddLog(text, "error") + raise Exception(err) + #end define + + def SetStartBlock(self, workchain, shardchain, seqno): + workchainType = type(workchain) + shardchainType = type(shardchain) + seqnoType = type(seqno) + if workchainType != int: + raise Exception(f"SetStartBlock error: workchain type mast be int, not {workchainType}") + if shardchainType != str: + raise Exception(f"SetStartBlock error: shardchain type mast be str, not {shardchainType}") + if seqnoType != int: + raise Exception(f"SetStartBlock error: seqno type mast be int, not {seqnoType}") + #end if + + block = Block() + block.workchain = workchain + block.shardchain = shardchain + block.seqno = seqno + if workchain == -1: + self.prevMasterBlock = block + else: + self.SetShardPrevBlock(block) + self.sync = True + #end define + + def ThreadBalancing(self): + while True: + tnum = threading.active_count() + if tnum > 100: + self.delay += 0.1 + elif tnum > 50: + self.delay += 0.01 + elif tnum < 50: + self.delay -= 0.1 + elif tnum < 100: + self.delay -= 0.01 + if self.delay < 0: + self.delay = 0 + if self.closing is True: + exit() + time.sleep(0.1) + #end define + + def StatusReading(self): + while True: + validatorStatus = self.ton.GetValidatorStatus() + validatorOutOfSync = validatorStatus.get("outOfSync") + if self.ton.liteClient.pubkeyPath is None: + self.working = False + self.closing = True + text = "TonBlocksScanner error: local liteserver is not configured, stop thread." + self.AddLog(text, "error") + exit() + if validatorOutOfSync > 20: + self.working = False + text = f"TonBlocksScanner warning: local liteserver is out of sync: {validatorOutOfSync}." + self.AddLog(text, "warning") + else: + self.working = True + time.sleep(10) + #end define + + def ScanBlocks(self): + while True: + if self.working is True: + self.ScanBlock() + if self.closing is True: + exit() + time.sleep(1) + #end define + + def ScanBlock(self): + block = self.Try(self.ton.GetLastBlock) + self.StartThread(self.SearchMissBlocks, args=(block, self.prevMasterBlock)) + if block != self.prevMasterBlock: + self.StartWithMode(self.ReadBlock, args=(block,)) + self.prevMasterBlock = block + #end define + + def ReadBlock(self, block): + self.StartWithMode(self.NewBlockReaction, args=(block,)) + shards = self.Try(self.ton.GetShards, args=(block,)) + for shard in shards: + self.StartThread(self.ReadShard, args=(shard,)) + #end define + + def ReadShard(self, shard): + block = shard.get("block") + prevBlock = self.GetShardPrevBlock(block.shardchain) + self.StartThread(self.SearchMissBlocks, args=(block, prevBlock)) + if block != prevBlock: + self.StartWithMode(self.NewBlockReaction, args=(block,)) + self.SetShardPrevBlock(block) + #end define + + def SearchMissBlocks(self, block, prevBlock): + if prevBlock is None: + return + diff = block.seqno - prevBlock.seqno + #for i in range(1, diff): + for i in range(diff-1, 0, -1): + workchain = block.workchain + shardchain = block.shardchain + seqno = block.seqno - i + self.StartWithMode(self.SearchBlock, args=(workchain, shardchain, seqno)) + #end define + + def SearchBlock(self, workchain, shardchain, seqno): + if self.delay != 0: + time.sleep(self.delay) + block = self.Try(self.ton.GetBlock, args=(workchain, shardchain, seqno)) + self.StartWithMode(self.NewBlockReaction, args=(block,)) + #end define + + def GetShardPrevBlock(self, shardchain): + prevBlock = self.prevShardsBlock.get(shardchain) + return prevBlock + #end define + + def SetShardPrevBlock(self, prevBlock): + self.prevShardsBlock[prevBlock.shardchain] = prevBlock + #end define + + def NewBlockReaction(self, block): + #print(f"{bcolors.green} block: {bcolors.endc} {block}") + self.blocksNum += 1 + if self.nbr: + self.StartThread(self.nbr, args=(block,)) + transactions = self.Try(self.ton.GetTransactions, args=(block,)) + for trans in transactions: + self.StartWithMode(self.NewTransReaction, args=(trans,)) + #end define + + def NewTransReaction(self, trans): + #print(f"{bcolors.magenta} trans: {bcolors.endc} {self.transNum}", "debug") + self.transNum += 1 + if self.ntr: + self.StartThread(self.ntr, args=(trans,)) + messageList = self.Try(self.ton.GetTrans, args=(trans,)) + for message in messageList: + self.NewMessageReaction(message) + #end define + + def NewMessageReaction(self, message): + if self.nmr: + self.StartThread(self.nmr, args=(message,)) + #print(f"{bcolors.yellow} message: {bcolors.endc} {message}") + #end define +#end class diff --git a/mytoncore/utils.py b/mytoncore/utils.py new file mode 100644 index 00000000..9743b0fc --- /dev/null +++ b/mytoncore/utils.py @@ -0,0 +1,79 @@ +import base64 +import json + + +def str2b64(s): + b = s.encode("utf-8") + b64 = base64.b64encode(b) + b64 = b64.decode("utf-8") + return b64 +# end define + + +def b642str(b64): + b64 = b64.encode("utf-8") + b = base64.b64decode(b64) + s = b.decode("utf-8") + return s +# end define + + +def dict2b64(d): + s = json.dumps(d) + b64 = str2b64(s) + return b64 +# end define + + +def b642dict(b64): + s = b642str(b64) + d = json.loads(s) + return d +# end define + + +def hex2b64(input): # TODO: remove duplicates + hexBytes = bytes.fromhex(input) + b64Bytes = base64.b64encode(hexBytes) + b64String = b64Bytes.decode() + return b64String +# end define + + +def b642hex(input): + b64Bytes = input.encode() + hexBytes = base64.b64decode(b64Bytes) + hexString = hexBytes.hex() + return hexString +# end define + + +def xhex2hex(x): + try: + b = x[1:] + h = b.lower() + return h + except: + return None +#end define + +def hex2base64(h): # TODO: remove duplicates + b = bytes.fromhex(h) + b64 = base64.b64encode(b) + s = b64.decode("utf-8") + return s +#end define + + +def str2bool(str): + if str == "true": + return True + return False +# end define + + +def ng2g(ng): + if ng is None: + return + return int(ng)/10**9 +#end define diff --git a/mytoncore/validator_console.py b/mytoncore/validator_console.py new file mode 100644 index 00000000..85d44891 --- /dev/null +++ b/mytoncore/validator_console.py @@ -0,0 +1,27 @@ +import subprocess + + +class ValidatorConsole: + def __init__(self, local): + self.local = local + self.appPath = None + self.privKeyPath = None + self.pubKeyPath = None + self.addr = None + #end define + + def Run(self, cmd, **kwargs): + console_timeout = self.local.db.console_timeout if self.local.db.console_timeout else 3 + timeout = kwargs.get("timeout", console_timeout) + if self.appPath is None or self.privKeyPath is None or self.pubKeyPath is None: + raise Exception("ValidatorConsole error: Validator console is not settings") + args = [self.appPath, "-k", self.privKeyPath, "-p", self.pubKeyPath, "-a", self.addr, "-v", "0", "--cmd", cmd] + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + output = process.stdout.decode("utf-8") + err = process.stderr.decode("utf-8") + if len(err) > 0: + self.local.add_log("args: {args}".format(args=args), "error") + raise Exception("ValidatorConsole error: {err}".format(err=err)) + return output + #end define +#end class diff --git a/mytonctrl/__init__.py b/mytonctrl/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mytonctrl/__main__.py b/mytonctrl/__main__.py new file mode 100644 index 00000000..22f2c85b --- /dev/null +++ b/mytonctrl/__main__.py @@ -0,0 +1,4 @@ +from mytonctrl.mytonctrl import mytonctrl + +if __name__ == '__main__': + mytonctrl() diff --git a/mytonctrl.py b/mytonctrl/mytonctrl.py similarity index 69% rename from mytonctrl.py rename to mytonctrl/mytonctrl.py index 09a91834..8fb1542c 100755 --- a/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1,75 +1,156 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*- +import subprocess +import json +import psutil +import inspect +import pkg_resources +import socket + +from shutil import copyfile +from functools import partial + +from mypylib.mypylib import ( + # GetGitAuthorAndRepo, + # GetGitBranch, + # GetGitHash, + # CheckGitUpdate, + # GetServiceStatus, + # GetServiceUptime, + # GetLoadAvg, + # RunAsRoot, + # time2human, + # timeago, + # Timestamp2Datetime, + # GetTimestamp, + # PrintTable, + # ColorPrint, + # ColorText, + # bcolors, + # MyPyClass, + + int2ip, + get_git_author_and_repo, + get_git_branch, + get_git_hash, + check_git_update, + get_service_status, + get_service_uptime, + get_load_avg, + run_as_root, + time2human, + timeago, + timestamp2datetime, + get_timestamp, + print_table, + color_print, + color_text, + bcolors, + MyPyClass +) + +from mypyconsole.mypyconsole import MyPyConsole +from mytoncore.mytoncore import MyTonCore +from mytoncore.functions import ( + Slashing, + Elections, + GetMemoryInfo, + GetSwapInfo, + GetBinGitHash, +) -from mypylib.mypylib import * -from mypyconsole.mypyconsole import * -from mytoncore import * import sys, getopt, os -local = MyPyClass(__file__) -console = MyPyConsole() -ton = MyTonCore() -def Init(argv): +def Init(local, ton, console, argv): # Load translate table - local.init_translator(local.buffer.my_dir + "translate.json") + translate_path = pkg_resources.resource_filename('mytonctrl', 'resources/translate.json') + local.init_translator(translate_path) + + # this function substitutes local and ton instances if function has this args + def inject_globals(func): + args = [] + for arg_name in inspect.getfullargspec(func)[0]: + if arg_name == 'local': + args.append(local) + elif arg_name == 'ton': + args.append(ton) + return partial(func, *args) # Create user console console.name = "MyTonCtrl" - console.startFunction = PreUp - - console.AddItem("update", Update, local.translate("update_cmd")) - console.AddItem("upgrade", Upgrade, local.translate("upgrade_cmd")) - console.AddItem("installer", Installer, local.translate("installer_cmd")) - console.AddItem("status", PrintStatus, local.translate("status_cmd")) - console.AddItem("seqno", Seqno, local.translate("seqno_cmd")) - console.AddItem("getconfig", GetConfig, local.translate("getconfig_cmd")) - - console.AddItem("nw", CreatNewWallet, local.translate("nw_cmd")) - console.AddItem("aw", ActivateWallet, local.translate("aw_cmd")) - console.AddItem("wl", PrintWalletsList, local.translate("wl_cmd")) - console.AddItem("iw", ImportWallet, local.translate("iw_cmd")) - console.AddItem("swv", SetWalletVersion, local.translate("swv_cmd")) - console.AddItem("ew", ExportWallet, local.translate("ex_cmd")) - console.AddItem("dw", DeleteWallet, local.translate("dw_cmd")) - - console.AddItem("vas", ViewAccountStatus, local.translate("vas_cmd")) - console.AddItem("vah", ViewAccountHistory, local.translate("vah_cmd")) - console.AddItem("mg", MoveCoins, local.translate("mg_cmd")) - console.AddItem("mgtp", MoveCoinsThroughProxy, local.translate("mgtp_cmd")) - - console.AddItem("nb", CreatNewBookmark, local.translate("nb_cmd")) - console.AddItem("bl", PrintBookmarksList, local.translate("bl_cmd")) - console.AddItem("db", DeleteBookmark, local.translate("db_cmd")) - - console.AddItem("nd", NewDomain, local.translate("nd_cmd")) - console.AddItem("dl", PrintDomainsList, local.translate("dl_cmd")) - console.AddItem("vds", ViewDomainStatus, local.translate("vds_cmd")) - console.AddItem("dd", DeleteDomain, local.translate("dd_cmd")) - console.AddItem("gdfa", GetDomainFromAuction, local.translate("gdfa_cmd")) - - console.AddItem("ol", PrintOffersList, local.translate("ol_cmd")) - console.AddItem("vo", VoteOffer, local.translate("vo_cmd")) - console.AddItem("od", OfferDiff, local.translate("od_cmd")) - - console.AddItem("el", PrintElectionEntriesList, local.translate("el_cmd")) - console.AddItem("ve", VoteElectionEntry, local.translate("ve_cmd")) - console.AddItem("vl", PrintValidatorList, local.translate("vl_cmd")) - console.AddItem("cl", PrintComplaintsList, local.translate("cl_cmd")) - console.AddItem("vc", VoteComplaint, local.translate("vc_cmd")) - - console.AddItem("get", GetSettings, local.translate("get_cmd")) - console.AddItem("set", SetSettings, local.translate("set_cmd")) - console.AddItem("xrestart", Xrestart, local.translate("xrestart_cmd")) - console.AddItem("xlist", Xlist, local.translate("xlist_cmd")) - - console.AddItem("new_pool", NewPool, local.translate("new_pool_cmd")) - console.AddItem("pools_list", PrintPoolsList, local.translate("pools_list_cmd")) - console.AddItem("get_pool_data", GetPoolData, local.translate("get_pool_data_cmd")) - console.AddItem("activate_pool", ActivatePool, local.translate("activate_pool_cmd")) - console.AddItem("deposit_to_pool", DepositToPool, local.translate("deposit_to_pool_cmd")) - console.AddItem("withdraw_from_pool", WithdrawFromPool, local.translate("withdraw_from_pool_cmd")) - console.AddItem("delete_pool", DeletePool, local.translate("delete_pool_cmd")) + console.startFunction = inject_globals(PreUp) + + console.AddItem("update", inject_globals(Update), local.translate("update_cmd")) + console.AddItem("upgrade", inject_globals(Upgrade), local.translate("upgrade_cmd")) + console.AddItem("installer", inject_globals(Installer), local.translate("installer_cmd")) + console.AddItem("status", inject_globals(PrintStatus), local.translate("status_cmd")) + console.AddItem("seqno", inject_globals(Seqno), local.translate("seqno_cmd")) + console.AddItem("getconfig", inject_globals(GetConfig), local.translate("getconfig_cmd")) + + console.AddItem("nw", inject_globals(CreatNewWallet), local.translate("nw_cmd")) + console.AddItem("aw", inject_globals(ActivateWallet), local.translate("aw_cmd")) + console.AddItem("wl", inject_globals(PrintWalletsList), local.translate("wl_cmd")) + console.AddItem("iw", inject_globals(ImportWallet), local.translate("iw_cmd")) + console.AddItem("swv", inject_globals(SetWalletVersion), local.translate("swv_cmd")) + console.AddItem("ew", inject_globals(ExportWallet), local.translate("ex_cmd")) + console.AddItem("dw", inject_globals(DeleteWallet), local.translate("dw_cmd")) + + console.AddItem("vas", inject_globals(ViewAccountStatus), local.translate("vas_cmd")) + console.AddItem("vah", inject_globals(ViewAccountHistory), local.translate("vah_cmd")) + console.AddItem("mg", inject_globals(MoveCoins), local.translate("mg_cmd")) + console.AddItem("mgtp", inject_globals(MoveCoinsThroughProxy), local.translate("mgtp_cmd")) + + console.AddItem("nb", inject_globals(CreatNewBookmark), local.translate("nb_cmd")) + console.AddItem("bl", inject_globals(PrintBookmarksList), local.translate("bl_cmd")) + console.AddItem("db", inject_globals(DeleteBookmark), local.translate("db_cmd")) + + # console.AddItem("nr", inject_globals(CreatNewAutoTransferRule), local.translate("nr_cmd")) # "Добавить правило автопереводов в расписание / Create new auto transfer rule" + # console.AddItem("rl", inject_globals(PrintAutoTransferRulesList), local.translate("rl_cmd")) # "Показать правила автопереводов / Show auto transfer rule list" + # console.AddItem("dr", inject_globals(DeleteAutoTransferRule), local.translate("dr_cmd")) # "Удалить правило автопереводов из расписания / Delete auto transfer rule" + + console.AddItem("nd", inject_globals(NewDomain), local.translate("nd_cmd")) + console.AddItem("dl", inject_globals(PrintDomainsList), local.translate("dl_cmd")) + console.AddItem("vds", inject_globals(ViewDomainStatus), local.translate("vds_cmd")) + console.AddItem("dd", inject_globals(DeleteDomain), local.translate("dd_cmd")) + console.AddItem("gdfa", inject_globals(GetDomainFromAuction), local.translate("gdfa_cmd")) + + console.AddItem("ol", inject_globals(PrintOffersList), local.translate("ol_cmd")) + console.AddItem("vo", inject_globals(VoteOffer), local.translate("vo_cmd")) + console.AddItem("od", inject_globals(OfferDiff), local.translate("od_cmd")) + + console.AddItem("el", inject_globals(PrintElectionEntriesList), local.translate("el_cmd")) + console.AddItem("ve", inject_globals(VoteElectionEntry), local.translate("ve_cmd")) + console.AddItem("vl", inject_globals(PrintValidatorList), local.translate("vl_cmd")) + console.AddItem("cl", inject_globals(PrintComplaintsList), local.translate("cl_cmd")) + console.AddItem("vc", inject_globals(VoteComplaint), local.translate("vc_cmd")) + + console.AddItem("get", inject_globals(GetSettings), local.translate("get_cmd")) + console.AddItem("set", inject_globals(SetSettings), local.translate("set_cmd")) + console.AddItem("xrestart", inject_globals(Xrestart), local.translate("xrestart_cmd")) + console.AddItem("xlist", inject_globals(Xlist), local.translate("xlist_cmd")) + #console.AddItem("gpk", inject_globals(GetPubKey), local.translate("gpk_cmd")) + #console.AddItem("ssoc", inject_globals(SignShardOverlayCert), local.translate("ssoc_cmd")) + #console.AddItem("isoc", inject_globals(ImportShardOverlayCert), local.translate("isoc_cmd")) + + #console.AddItem("new_nomination_controller", inject_globals(NewNominationController), local.translate("new_controller_cmd")) + #console.AddItem("get_nomination_controller_data", inject_globals(GetNominationControllerData), local.translate("get_nomination_controller_data_cmd")) + #console.AddItem("deposit_to_nomination_controller", inject_globals(DepositToNominationController), local.translate("deposit_to_controller_cmd")) + #console.AddItem("withdraw_from_nomination_controller", inject_globals(WithdrawFromNominationController), local.translate("withdraw_from_nomination_controller_cmd")) + #console.AddItem("request_to_nomination_controller", inject_globals(SendRequestToNominationController), local.translate("request_to_nomination_controller_cmd")) + #console.AddItem("new_restricted_wallet", inject_globals(NewRestrictedWallet), local.translate("new_restricted_wallet_cmd")) + + console.AddItem("new_pool", inject_globals(NewPool), local.translate("new_pool_cmd")) + console.AddItem("pools_list", inject_globals(PrintPoolsList), local.translate("pools_list_cmd")) + console.AddItem("get_pool_data", inject_globals(GetPoolData), local.translate("get_pool_data_cmd")) + console.AddItem("activate_pool", inject_globals(ActivatePool), local.translate("activate_pool_cmd")) + console.AddItem("deposit_to_pool", inject_globals(DepositToPool), local.translate("deposit_to_pool_cmd")) + console.AddItem("withdraw_from_pool", inject_globals(WithdrawFromPool), local.translate("withdraw_from_pool_cmd")) + console.AddItem("delete_pool", inject_globals(DeletePool), local.translate("delete_pool_cmd")) + #console.AddItem("update_validator_set", inject_globals(UpdateValidatorSet), local.translate("update_validator_set_cmd")) + + # console.AddItem("pt", inject_globals(PrintTest), "PrintTest") + # console.AddItem("sl", inject_globals(sl), "sl") # Process input parameters opts, args = getopt.getopt(argv,"hc:w:",["config=","wallets="]) @@ -101,14 +182,15 @@ def Init(argv): local.run() #end define -def PreUp(): - CheckMytonctrlUpdate() - check_vport() +def PreUp(local, ton): + CheckMytonctrlUpdate(local) + check_vport(local, ton) # CheckTonUpdate() #end define def Installer(args): - args = ["python3", "/usr/src/mytonctrl/mytoninstaller.py"] + # args = ["python3", "/usr/src/mytonctrl/mytoninstaller.py"] + args = ["python3", "-m", "mytoninstaller"] subprocess.run(args) #end define @@ -118,7 +200,27 @@ def GetItemFromList(data, index): except: pass #end define -def check_vport(): +def GetAuthorRepoBranchFromArgs(args): + data = dict() + arg1 = GetItemFromList(args, 0) + arg2 = GetItemFromList(args, 1) + if arg1: + if "https://" in arg1: + buff = arg1[8:].split('/') + print(f"buff: {buff}") + data["author"] = buff[1] + data["repo"] = buff[2] + tree = GetItemFromList(buff, 3) + if tree: + data["branch"] = GetItemFromList(buff, 4) + else: + data["branch"] = arg1 + if arg2: + data["branch"] = arg2 + return data +#end define + +def check_vport(local, ton): vconfig = ton.GetValidatorConfig() addr = vconfig.addrs.pop() ip = int2ip(addr.ip) @@ -133,26 +235,26 @@ def check_git(input_args, default_repo, text): git_path = f"{src_dir}/{default_repo}" default_author = "ton-blockchain" default_branch = "master" - + # Get author, repo, branch local_author, local_repo = get_git_author_and_repo(git_path) local_branch = get_git_branch(git_path) - + # Set author, repo, branch data = GetAuthorRepoBranchFromArgs(input_args) need_author = data.get("author") need_repo = data.get("repo") need_branch = data.get("branch") - + # Check if remote repo is different from default if ((need_author is None and local_author != default_author) or (need_repo is None and local_repo != default_repo)): remote_url = f"https://github.com/{local_author}/{local_repo}/tree/{need_branch if need_branch else local_branch}" - raise Exception(f"{text} error: You are on {remote_url} remote url, to {text} to the tip use `{text} {remote_url}` command") + raise Exception(f"{text} error: You are on {remote_url} remote url, to update to the tip use `{text} {remote_url}` command") elif need_branch is None and local_branch != default_branch: - raise Exception(f"{text} error: You are on {local_branch} branch, to {text} to the tip of {local_branch} branch use `{text} {local_branch}` command") + raise Exception(f"{text} error: You are on {local_branch} branch, to update to the tip of {local_branch} branch use `{text} {local_branch}` command") #end if - + if need_author is None: need_author = local_author if need_repo is None: @@ -160,36 +262,17 @@ def check_git(input_args, default_repo, text): if need_branch is None: need_branch = local_branch #end if - - return need_author, need_repo, need_branch -#end define -def GetAuthorRepoBranchFromArgs(args): - data = dict() - arg1 = GetItemFromList(args, 0) - arg2 = GetItemFromList(args, 1) - if arg1: - if "https://" in arg1: - buff = arg1[8:].split('/') - print(f"buff: {buff}") - data["author"] = buff[1] - data["repo"] = buff[2] - tree = GetItemFromList(buff, 3) - if tree: - data["branch"] = GetItemFromList(buff, 4) - else: - data["branch"] = arg1 - if arg2: - data["branch"] = arg2 - return data + return need_author, need_repo, need_branch #end define -def Update(args): +def Update(local, args): repo = "mytonctrl" author, repo, branch = check_git(args, repo, "update") # Run script - runArgs = ["bash", "/usr/src/mytonctrl/scripts/update.sh", "-a", author, "-r", repo, "-b", branch] + update_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/update.sh') + runArgs = ["bash", update_script_path, "-a", author, "-r", repo, "-b", branch] exitCode = run_as_root(runArgs) if exitCode == 0: text = "Update - {green}OK{endc}" @@ -199,10 +282,10 @@ def Update(args): local.exit() #end define -def Upgrade(args): +def Upgrade(ton, args): repo = "ton" author, repo, branch = check_git(args, repo, "upgrade") - + # bugfix if the files are in the wrong place liteClient = ton.GetSettings("liteClient") configPath = liteClient.get("configPath") @@ -220,11 +303,11 @@ def Upgrade(args): if "/usr/bin/ton" in pubKeyPath: validatorConsole["pubKeyPath"] = "/var/ton-work/keys/server.pub" ton.SetSettings("validatorConsole", validatorConsole) - + # Run script - runArgs = ["bash", "/usr/src/mytonctrl/scripts/upgrade.sh", "-a", author, "-r", repo, "-b", branch] + upgrade_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/upgrade.sh') + runArgs = ["bash", upgrade_script_path, "-a", author, "-r", repo, "-b", branch] exitCode = run_as_root(runArgs) - exitCode += run_as_root(["python3", "/usr/src/mytonctrl/scripts/upgrade.py"]) if exitCode == 0: text = "Upgrade - {green}OK{endc}" else: @@ -232,21 +315,29 @@ def Upgrade(args): color_print(text) #end define -def CheckMytonctrlUpdate(): +def CheckMytonctrlUpdate(local): git_path = local.buffer.my_dir result = check_git_update(git_path) if result is True: color_print(local.translate("mytonctrl_update_available")) #end define -def CheckTonUpdate(): +def CheckTonUpdate(local): git_path = "/usr/src/ton" result = check_git_update(git_path) if result is True: color_print(local.translate("ton_update_available")) #end define -def PrintStatus(args): +def PrintTest(local, args): + print(json.dumps(local.buffer, indent=2)) +#end define + +def sl(ton, args): + Slashing(ton.local, ton) +#end define + +def PrintStatus(local, ton, args): opt = None if len(args) == 1: opt = args[0] @@ -289,13 +380,13 @@ def PrintStatus(args): validatorAccount = ton.GetAccount(validatorWallet.addrB64) else: validatorAccount = None - PrintTonStatus(startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) - PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg) - PrintTonConfig(fullConfigAddr, fullElectorAddr, config15, config17) - PrintTimes(rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) + 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) #end define -def PrintTonStatus(startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): +def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): tps1 = tpsAvg[0] tps5 = tpsAvg[1] tps15 = tpsAvg[2] @@ -335,7 +426,7 @@ def PrintTonStatus(startWorkTime, totalValidators, onlineValidators, shardsNumbe print() #end define -def PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg): +def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg): if validatorWallet is None: return walletAddr = validatorWallet.addrB64 @@ -389,11 +480,11 @@ def PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWal # Disks status disksLoad_data = list() for key, item in disksLoadAvg.items(): - diskLoad1_text = bcolors.green_text(item[0]) - diskLoad5_text = bcolors.green_text(item[1]) + diskLoad1_text = bcolors.green_text(item[0]) # TODO: this variables is unused. Why? + diskLoad5_text = bcolors.green_text(item[1]) # TODO: this variables is unused. Why? diskLoad15_text = bcolors.green_text(item[2]) - diskLoadPercent1_text = GetColorInt(disksLoadPercentAvg[key][0], 80, logic="less", ending="%") - diskLoadPercent5_text = GetColorInt(disksLoadPercentAvg[key][1], 80, logic="less", ending="%") + diskLoadPercent1_text = GetColorInt(disksLoadPercentAvg[key][0], 80, logic="less", ending="%") # TODO: this variables is unused. Why? + diskLoadPercent5_text = GetColorInt(disksLoadPercentAvg[key][1], 80, logic="less", ending="%") # TODO: this variables is unused. Why? diskLoadPercent15_text = GetColorInt(disksLoadPercentAvg[key][2], 80, logic="less", ending="%") buff = "{}, {}" buff = "{}{}:[{}{}{}]{}".format(bcolors.cyan, key, bcolors.default, buff, bcolors.cyan, bcolors.endc) @@ -477,7 +568,7 @@ def GetColorStatus(input): return result #end define -def PrintTonConfig(fullConfigAddr, fullElectorAddr, config15, config17): +def PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17): validatorsElectedFor = config15["validatorsElectedFor"] electionsStartBefore = config15["electionsStartBefore"] electionsEndBefore = config15["electionsEndBefore"] @@ -504,7 +595,7 @@ def PrintTonConfig(fullConfigAddr, fullElectorAddr, config15, config17): print() #end define -def PrintTimes(rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15): +def PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15): validatorsElectedFor = config15["validatorsElectedFor"] electionsStartBefore = config15["electionsStartBefore"] electionsEndBefore = config15["electionsEndBefore"] @@ -546,7 +637,7 @@ def PrintTimes(rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, co #end define def GetColorTime(datetime, timestamp): - newTimestamp = get_timestamp() + newTimestamp = GetTimestamp() if timestamp > newTimestamp: result = bcolors.green_text(datetime) else: @@ -554,7 +645,7 @@ def GetColorTime(datetime, timestamp): return result #end define -def Seqno(args): +def Seqno(ton, args): try: walletName = args[0] except: @@ -565,7 +656,7 @@ def Seqno(args): print(walletName, "seqno:", seqno) #end define -def CreatNewWallet(args): +def CreatNewWallet(ton, args): version = "v1" try: if len(args) == 0: @@ -587,10 +678,10 @@ def CreatNewWallet(args): table = list() table += [["Name", "Workchain", "Address"]] table += [[wallet.name, wallet.workchain, wallet.addrB64_init]] - print_table(table) + PrintTable(table) #end define -def ActivateWallet(args): +def ActivateWallet(local, ton, args): try: walletName = args[0] except Exception as err: @@ -606,7 +697,7 @@ def ActivateWallet(args): color_print("ActivateWallet - {green}OK{endc}") #end define -def PrintWalletsList(args): +def PrintWalletsList(ton, args): table = list() table += [["Name", "Status", "Balance", "Ver", "Wch", "Address"]] data = ton.GetWallets() @@ -618,10 +709,10 @@ def PrintWalletsList(args): if account.status != "active": wallet.addrB64 = wallet.addrB64_init table += [[wallet.name, account.status, account.balance, wallet.version, wallet.workchain, wallet.addrB64]] - print_table(table) + PrintTable(table) #end define -def ImportWalletFromFile(args): +def ImportWalletFromFile(local, ton, args): try: filePath = args[0] except: @@ -646,7 +737,7 @@ def ImportWalletFromFile(args): color_print("ImportWalletFromFile - {green}OK{endc}") #end define -def ImportWallet(args): +def ImportWallet(ton, args): try: addr = args[0] key = args[1] @@ -657,7 +748,7 @@ def ImportWallet(args): print("Wallet name:", name) #end define -def SetWalletVersion(args): +def SetWalletVersion(ton, args): try: addr = args[0] version = args[1] @@ -668,7 +759,7 @@ def SetWalletVersion(args): color_print("SetWalletVersion - {green}OK{endc}") #end define -def ExportWallet(args): +def ExportWallet(ton, args): try: name = args[0] except: @@ -680,7 +771,7 @@ def ExportWallet(args): print("Secret key:", key) #end define -def DeleteWallet(args): +def DeleteWallet(ton, args): try: walletName = args[0] except: @@ -694,7 +785,7 @@ def DeleteWallet(args): color_print("DeleteWallet - {green}OK{endc}") #end define -def ViewAccountStatus(args): +def ViewAccountStatus(ton, args): try: addrB64 = args[0] except: @@ -706,24 +797,24 @@ def ViewAccountStatus(args): statusTable = list() statusTable += [["Address", "Status", "Version", "Balance"]] statusTable += [[addrB64, account.status, version, account.balance]] - historyTable = GetHistoryTable(addrB64, 10) - print_table(statusTable) + historyTable = GetHistoryTable(ton, addrB64, 10) + PrintTable(statusTable) print() - print_table(historyTable) + PrintTable(historyTable) #end define -def ViewAccountHistory(args): +def ViewAccountHistory(ton, args): try: addr = args[0] limit = int(args[1]) except: color_print("{red}Bad args. Usage:{endc} vah ") return - table = GetHistoryTable(addr, limit) - print_table(table) + table = GetHistoryTable(ton, addr, limit) + PrintTable(table) #end define -def GetHistoryTable(addr, limit): +def GetHistoryTable(ton, addr, limit): addr = ton.GetDestinationAddr(addr) account = ton.GetAccount(addr) history = ton.GetAccountHistory(account, limit) @@ -748,7 +839,7 @@ def GetHistoryTable(addr, limit): return table #end define -def MoveCoins(args): +def MoveCoins(ton, args): try: walletName = args[0] destination = args[1] @@ -763,7 +854,7 @@ def MoveCoins(args): color_print("MoveCoins - {green}OK{endc}") #end define -def MoveCoinsThroughProxy(args): +def MoveCoinsThroughProxy(ton, args): try: walletName = args[0] destination = args[1] @@ -777,7 +868,7 @@ def MoveCoinsThroughProxy(args): color_print("MoveCoinsThroughProxy - {green}OK{endc}") #end define -def CreatNewBookmark(args): +def CreatNewBookmark(ton, args): try: name = args[0] addr = args[1] @@ -798,7 +889,7 @@ def CreatNewBookmark(args): color_print("CreatNewBookmark - {green}OK{endc}") #end define -def PrintBookmarksList(args): +def PrintBookmarksList(ton, args): data = ton.GetBookmarks() if (data is None or len(data) == 0): print("No data") @@ -811,10 +902,10 @@ def PrintBookmarksList(args): addr = item.get("addr") data = item.get("data") table += [[name, type, addr, data]] - print_table(table) + PrintTable(table) #end define -def DeleteBookmark(args): +def DeleteBookmark(ton, args): try: name = args[0] type = args[1] @@ -825,7 +916,37 @@ def DeleteBookmark(args): color_print("DeleteBookmark - {green}OK{endc}") #end define -def PrintOffersList(args): +# def CreatNewAutoTransferRule(args): +# try: +# name = args[0] +# addr = args[1] +# except: +# color_print("{red}Bad args. Usage:{endc} nr ") +# return +# rule = dict() +# rule["name"] = name +# rule["addr"] = addr +# ton.AddAutoTransferRule(rule) +# color_print("CreatNewAutoTransferRule - {green}OK{endc}") +# #end define + +# def PrintAutoTransferRulesList(args): +# data = ton.GetRules() +# if (data is None or len(data) == 0): +# print("No data") +# return +# table = list() +# table += [["Name", "fix me"]] +# for item in data: +# table += [[item.get("name"), item.get("fix me")]] +# PrintTable(table) +# #end define + +# def DeleteAutoTransferRule(args): +# print("fix me") +# #end define + +def PrintOffersList(ton, args): offers = ton.GetOffers() if "--json" in args: text = json.dumps(offers, indent=2) @@ -849,10 +970,10 @@ def PrintOffersList(args): if isPassed == False: isPassed = bcolors.red_text("false") table += [[hash, votedValidators, wl, approvedPercent_text, isPassed]] - print_table(table) + PrintTable(table) #end define -def VoteOffer(args): +def VoteOffer(ton, args): if len(args) == 0: color_print("{red}Bad args. Usage:{endc} vo ") return @@ -861,7 +982,7 @@ def VoteOffer(args): color_print("VoteOffer - {green}OK{endc}") #end define -def OfferDiff(args): +def OfferDiff(ton, args): try: offerHash = args[0] offerHash = offerHash @@ -871,7 +992,7 @@ def OfferDiff(args): ton.GetOfferDiff(offerHash) #end define -def GetConfig(args): +def GetConfig(ton, args): try: configId = args[0] configId = int(configId) @@ -883,7 +1004,7 @@ def GetConfig(args): print(text) #end define -def PrintComplaintsList(args): +def PrintComplaintsList(ton, args): past = "past" in args complaints = ton.GetComplaints(past=past) if "--json" in args: @@ -909,10 +1030,10 @@ def PrintComplaintsList(args): if isPassed == False: isPassed = bcolors.red_text("false") table += [[electionId, adnl, Fine_text, votedValidators, approvedPercent_text, isPassed]] - print_table(table) + PrintTable(table) #end define -def VoteComplaint(args): +def VoteComplaint(ton, args): try: electionId = args[0] complaintHash = args[1] @@ -923,7 +1044,7 @@ def VoteComplaint(args): color_print("VoteComplaint - {green}OK{endc}") #end define -def NewDomain(args): +def NewDomain(ton, args): try: domainName = args[0] walletName = args[1] @@ -939,7 +1060,7 @@ def NewDomain(args): color_print("NewDomain - {green}OK{endc}") #end define -def PrintDomainsList(args): +def PrintDomainsList(ton, args): data = ton.GetDomains() if (data is None or len(data) == 0): print("No data") @@ -953,10 +1074,10 @@ def PrintDomainsList(args): endTime = timestamp2datetime(endTime, "%d.%m.%Y") adnlAddr = item.get("adnlAddr") table += [[domainName, walletName, endTime, adnlAddr]] - print_table(table) + PrintTable(table) #end define -def ViewDomainStatus(args): +def ViewDomainStatus(ton, args): try: domainName = args[0] except: @@ -972,7 +1093,7 @@ def ViewDomainStatus(args): print_table(table) #end define -def DeleteDomain(args): +def DeleteDomain(ton, args): try: domainName = args[0] except: @@ -982,7 +1103,7 @@ def DeleteDomain(args): color_print("DeleteDomain - {green}OK{endc}") #end define -def GetDomainFromAuction(args): +def GetDomainFromAuction(ton, args): try: walletName = args[0] addr = args[1] @@ -993,7 +1114,7 @@ def GetDomainFromAuction(args): color_print("GetDomainFromAuction - {green}OK{endc}") #end define -def PrintElectionEntriesList(args): +def PrintElectionEntriesList(ton, args): past = "past" in args entries = ton.GetElectionEntries(past=past) if "--json" in args: @@ -1018,12 +1139,12 @@ def PrintElectionEntriesList(args): print_table(table) #end define -def VoteElectionEntry(args): - Elections(ton) +def VoteElectionEntry(ton, args): + Elections(ton.local, ton) color_print("VoteElectionEntry - {green}OK{endc}") #end define -def PrintValidatorList(args): +def PrintValidatorList(ton, args): past = "past" in args validators = ton.GetValidatorsList(past=past) if "--json" in args: @@ -1064,7 +1185,7 @@ def Reduct(item): return result #end define -def GetSettings(args): +def GetSettings(ton, args): try: name = args[0] except: @@ -1074,14 +1195,14 @@ def GetSettings(args): print(json.dumps(result, indent=2)) #end define -def SetSettings(args): +def SetSettings(ton, args): try: name = args[0] value = args[1] except: color_print("{red}Bad args. Usage:{endc} set ") return - result = ton.SetSettings(name, value) + ton.SetSettings(name, value) color_print("SetSettings - {green}OK{endc}") #end define @@ -1089,7 +1210,8 @@ def Xrestart(inputArgs): if len(inputArgs) < 2: color_print("{red}Bad args. Usage:{endc} xrestart ") return - args = ["python3", "/usr/src/mytonctrl/scripts/xrestart.py"] + xrestart_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/xrestart.py') + args = ["python3", xrestart_script_path] # TODO: Fix path args += inputArgs exitCode = run_as_root(args) if exitCode == 0: @@ -1103,7 +1225,102 @@ def Xlist(args): color_print("Xlist - {green}OK{endc}") #end define -def NewPool(args): +def GetPubKey(ton, args): + adnlAddr = ton.GetAdnlAddr() + pubkey = ton.GetPubKey(adnlAddr) + print("pubkey:", pubkey) +#end define + +def SignShardOverlayCert(ton, args): + try: + adnl = args[0] + pubkey = args[0] + except: + color_print("{red}Bad args. Usage:{endc} ssoc ") + return + ton.SignShardOverlayCert(adnl, pubkey) +#end define + +def ImportShardOverlayCert(ton, args): + ton.ImportShardOverlayCert() +#end define + +def NewNominationController(ton, args): + try: + name = args[0] + nominatorAddr = args[1] + rewardShare = args[2] + coverAbility = args[3] + except: + color_print("{red}Bad args. Usage:{endc} new_controller ") + return + ton.CreateNominationController(name, nominatorAddr, rewardShare=rewardShare, coverAbility=coverAbility) + color_print("NewNominationController - {green}OK{endc}") +#end define + +def GetNominationControllerData(ton, args): + try: + addrB64 = args[0] + except: + color_print("{red}Bad args. Usage:{endc} get_nomination_controller_data ") + return + addrB64 = ton.GetDestinationAddr(addrB64) + controllerData = ton.GetControllerData(addrB64) + print(json.dumps(controllerData, indent=4)) +#end define + +def DepositToNominationController(ton, args): + try: + walletName = args[0] + destination = args[1] + amount = float(args[2]) + except: + color_print("{red}Bad args. Usage:{endc} add_to_nomination_controller ") + return + destination = ton.GetDestinationAddr(destination) + ton.DepositToNominationController(walletName, destination, amount) + color_print("DepositToNominationController - {green}OK{endc}") +#end define + +def WithdrawFromNominationController(ton, args): + try: + walletName = args[0] + destination = args[1] + amount = float(args[2]) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_nomination_controller ") + return + destination = ton.GetDestinationAddr(destination) + ton.WithdrawFromNominationController(walletName, destination, amount) + color_print("WithdrawFromNominationController - {green}OK{endc}") +#end define + +def SendRequestToNominationController(ton, args): + try: + walletName = args[0] + destination = args[1] + except: + color_print("{red}Bad args. Usage:{endc} request_to_nomination_controller ") + return + destination = ton.GetDestinationAddr(destination) + ton.SendRequestToNominationController(walletName, destination) + color_print("SendRequestToNominationController - {green}OK{endc}") +#end define + +def NewRestrictedWallet(ton, args): + try: + workchain = int(args[0]) + name = args[1] + ownerAddr = args[2] + #subwallet = args[3] + except: + color_print("{red}Bad args. Usage:{endc} new_restricted_wallet ") + return + ton.CreateRestrictedWallet(name, ownerAddr, workchain=workchain) + color_print("NewRestrictedWallet - {green}OK{endc}") +#end define + +def NewPool(ton, args): try: poolName = args[0] validatorRewardSharePercent = float(args[1]) @@ -1117,7 +1334,7 @@ def NewPool(args): color_print("NewPool - {green}OK{endc}") #end define -def ActivatePool(args): +def ActivatePool(local, ton, args): try: poolName = args[0] except: @@ -1131,7 +1348,7 @@ def ActivatePool(args): color_print("ActivatePool - {green}OK{endc}") #end define -def PrintPoolsList(args): +def PrintPoolsList(ton, args): table = list() table += [["Name", "Status", "Balance", "Address"]] data = ton.GetPools() @@ -1146,7 +1363,7 @@ def PrintPoolsList(args): print_table(table) #end define -def GetPoolData(args): +def GetPoolData(ton, args): try: poolName = args[0] except: @@ -1161,7 +1378,7 @@ def GetPoolData(args): print(json.dumps(poolData, indent=4)) #end define -def DepositToPool(args): +def DepositToPool(ton, args): try: walletName = args[0] pollAddr = args[1] @@ -1173,7 +1390,7 @@ def DepositToPool(args): color_print("DepositToPool - {green}OK{endc}") #end define -def WithdrawFromPool(args): +def WithdrawFromPool(ton, args): try: poolAddr = args[0] amount = float(args[1]) @@ -1184,7 +1401,7 @@ def WithdrawFromPool(args): color_print("WithdrawFromPool - {green}OK{endc}") #end define -def DeletePool(args): +def DeletePool(ton, args): try: poolName = args[0] except: @@ -1195,14 +1412,14 @@ def DeletePool(args): color_print("DeletePool - {green}OK{endc}") #end define -def UpdateValidatorSet(args): +def UpdateValidatorSet(ton, args): try: poolAddr = args[0] except: color_print("{red}Bad args. Usage:{endc} update_validator_set ") return - wallet = self.GetValidatorWallet() - self.PoolUpdateValidatorSet(poolAddr, wallet) + wallet = ton.GetValidatorWallet() + ton.PoolUpdateValidatorSet(poolAddr, wallet) color_print("DeletePool - {green}OK{endc}") #end define @@ -1211,7 +1428,12 @@ def UpdateValidatorSet(args): ### Start of the program ### -if __name__ == "__main__": - Init(sys.argv[1:]) +def mytonctrl(): + local = MyPyClass('mytonctrl.py') + mytoncore_local = MyPyClass('mytoncore.py') + ton = MyTonCore(mytoncore_local) + console = MyPyConsole() + + Init(local, ton, console, sys.argv[1:]) console.Run() -#end if +#end define diff --git a/translate.json b/mytonctrl/resources/translate.json similarity index 100% rename from translate.json rename to mytonctrl/resources/translate.json diff --git a/scripts/update.sh b/mytonctrl/scripts/update.sh similarity index 73% rename from scripts/update.sh rename to mytonctrl/scripts/update.sh index 6c17a217..e6b3f680 100644 --- a/scripts/update.sh +++ b/mytonctrl/scripts/update.sh @@ -28,17 +28,23 @@ done COLOR='\033[92m' ENDC='\033[0m' -# Установка компонентов python3 -pip3 install fastcrc - # Go to work dir cd ${srcdir} rm -rf ${srcdir}/${repo} # Update code echo "https://github.com/${author}/${repo}.git -> ${branch}" -git clone --recursive https://github.com/${author}/${repo}.git -cd ${repo} && git checkout ${branch} && git submodule update --init --recursive +git clone https://github.com/${author}/${repo}.git +cd ${repo} +git checkout ${branch} +git submodule update --init --recursive + +# FIXME: add __init__.py in these repos +touch mypyconsole/__init__.py +touch mypylib/__init__.py + +pip3 install -U . + systemctl restart mytoncore # Конец diff --git a/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh similarity index 92% rename from scripts/upgrade.sh rename to mytonctrl/scripts/upgrade.sh index 03ac0b44..2e845b03 100644 --- a/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -42,6 +42,10 @@ else cp /usr/bin/ton/validator-engine-console/client.pub /var/ton-work/keys/client.pub cp /usr/bin/ton/validator-engine-console/server.pub /var/ton-work/keys/server.pub cp /usr/bin/ton/validator-engine-console/liteserver.pub /var/ton-work/keys/liteserver.pub + + # fix validator.service + sed -i 's/validator-engine\/ton-global.config.json/global.config.json/' /etc/systemd/system/validator.service + systemctl daemon-reload fi # Go to work dir diff --git a/scripts/xrestart.py b/mytonctrl/scripts/xrestart.py similarity index 99% rename from scripts/xrestart.py rename to mytonctrl/scripts/xrestart.py index b367eb1f..797835a6 100644 --- a/scripts/xrestart.py +++ b/mytonctrl/scripts/xrestart.py @@ -70,4 +70,4 @@ def result(): if __name__ == "__main__": Xguard() -#end if \ No newline at end of file +#end if diff --git a/mytoninstaller/__init__.py b/mytoninstaller/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mytoninstaller/__main__.py b/mytoninstaller/__main__.py new file mode 100644 index 00000000..78efe3f2 --- /dev/null +++ b/mytoninstaller/__main__.py @@ -0,0 +1,5 @@ +from mytoninstaller.mytoninstaller import mytoninstaller + + +if __name__ == '__main__': + mytoninstaller() diff --git a/mytoninstaller/config.py b/mytoninstaller/config.py new file mode 100644 index 00000000..c1a78dd2 --- /dev/null +++ b/mytoninstaller/config.py @@ -0,0 +1,136 @@ +import os +import json +import subprocess +import requests +import base64 + +from mytoncore.utils import hex2b64, dict2b64 +from mytoninstaller.utils import StartMytoncore, GetInitBlock +from mypylib.mypylib import ip2int, Dict + + +defaultLocalConfigPath = "/usr/bin/ton/local.config.json" + + +def GetConfig(**kwargs): + path = kwargs.get("path") + file = open(path, 'rt') + text = file.read() + file.close() + config = Dict(json.loads(text)) + return config +#end define + + +def SetConfig(**kwargs): + path = kwargs.get("path") + data = kwargs.get("data") + + # write config + text = json.dumps(data, indent=4) + file = open(path, 'wt') + file.write(text) + file.close() +#end define + + +def BackupVconfig(local): + local.add_log("Backup validator config file 'config.json' to 'config.json.backup'", "debug") + vconfig_path = local.buffer.vconfig_path + backupPath = vconfig_path + ".backup" + args = ["cp", vconfig_path, backupPath] + subprocess.run(args) +#end define + + +def BackupMconfig(local): + local.add_log("Backup mytoncore config file 'mytoncore.db' to 'mytoncore.db.backup'", "debug") + mconfig_path = local.buffer.mconfig_path + backupPath = mconfig_path + ".backup" + args = ["cp", mconfig_path, backupPath] + subprocess.run(args) +#end define + + +def GetPortsFromVconfig(local): + vconfig_path = local.buffer.vconfig_path + + # read vconfig + local.add_log("read vconfig", "debug") + vconfig = GetConfig(path=vconfig_path) + + # read mconfig + local.add_log("read mconfig", "debug") + mconfig_path = local.buffer.mconfig_path + mconfig = GetConfig(path=mconfig_path) + + # edit mytoncore config file + local.add_log("edit mytoncore config file", "debug") + mconfig.liteClient.liteServer.port = mconfig.liteservers[0].port + mconfig.validatorConsole.addr = f"127.0.0.1:{mconfig.control[0].port}" + + # write mconfig + local.add_log("write mconfig", "debug") + SetConfig(path=mconfig_path, data=mconfig) + + # restart mytoncore + StartMytoncore(local) +#end define + + +def CreateLocalConfig(local, initBlock, localConfigPath=defaultLocalConfigPath): + # dirty hack, but GetInitBlock() function uses the same technique + from mytoncore import hex2base64 + + # read global config file + file = open("/usr/bin/ton/global.config.json", 'rt') + text = file.read() + data = json.loads(text) + file.close() + + # edit config + liteServerConfig = GetLiteServerConfig(local) + data["liteservers"] = [liteServerConfig] + data["validator"]["init_block"]["seqno"] = initBlock["seqno"] + data["validator"]["init_block"]["root_hash"] = hex2base64(initBlock["rootHash"]) + data["validator"]["init_block"]["file_hash"] = hex2base64(initBlock["fileHash"]) + text = json.dumps(data, indent=4) + + # write local config file + file = open(localConfigPath, 'wt') + file.write(text) + file.close() + + # chown + user = local.buffer.user + args = ["chown", "-R", user + ':' + user, localConfigPath] + + print("Local config file created:", localConfigPath) +#end define + + +def get_own_ip(): + requests.packages.urllib3.util.connection.HAS_IPV6 = False + ip = requests.get("https://ifconfig.me/ip").text + return ip +#end define + + +def GetLiteServerConfig(local): + keys_dir = local.buffer.keys_dir + liteserver_key = keys_dir + "liteserver" + liteserver_pubkey = liteserver_key + ".pub" + result = Dict() + file = open(liteserver_pubkey, 'rb') + data = file.read() + file.close() + key = base64.b64encode(data[4:]) + ip = get_own_ip() + mconfig = GetConfig(path=local.buffer.mconfig_path) + result.ip = ip2int(ip) + result.port = mconfig.liteClient.liteServer.port + result.id = Dict() + result.id["@type"]= "pub.ed25519" + result.id.key= key.decode() + return result +#end define diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py new file mode 100644 index 00000000..f284e61e --- /dev/null +++ b/mytoninstaller/mytoninstaller.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +# -*- coding: utf_8 -*- + +import os, sys +import inspect +import random +import json +import subprocess + +from mypylib.mypylib import MyPyClass, run_as_root +from mypyconsole.mypyconsole import MyPyConsole + +from mytoninstaller.config import GetLiteServerConfig +from mytoninstaller.utils import GetInitBlock +from mytoncore.utils import dict2b64, str2bool, b642dict + +from mytoninstaller.settings import ( + FirstNodeSettings, + FirstMytoncoreSettings, + EnableValidatorConsole, + EnableLiteServer, + EnableDhtServer, + EnableJsonRpc, + EnablePytonv3, + EnableTonHttpApi, + DangerousRecoveryValidatorConfigFile, + CreateSymlinks, +) +from mytoninstaller.config import ( + CreateLocalConfig, + BackupVconfig, + BackupMconfig, +) + +from functools import partial + + +def Init(local, console): + local.db.config.isStartOnlyOneProcess = False + local.db.config.logLevel = "debug" + local.db.config.isIgnorLogWarning = True # disable warning + local.run() + local.db.config.isIgnorLogWarning = False # enable warning + + + # create variables + user = os.environ.get("USER", "root") + local.buffer.user = user + local.buffer.vuser = "validator" + local.buffer.cport = random.randint(2000, 65000) + local.buffer.lport = random.randint(2000, 65000) + + # this funciton injects MyPyClass instance + def inject_globals(func): + args = [] + for arg_name in inspect.getfullargspec(func)[0]: + if arg_name == 'local': + args.append(local) + return partial(func, *args) + + # Create user console + console.name = "MyTonInstaller" + console.color = console.RED + console.AddItem("status", inject_globals(Status), "Print TON component status") + console.AddItem("enable", inject_globals(Enable), "Enable some function: 'FN' - Full node, 'VC' - Validator console, 'LS' - Liteserver, 'DS' - DHT-Server, 'JR' - jsonrpc, 'PT' - pyTONv3. Example: 'enable FN'") + console.AddItem("update", inject_globals(Enable), "Update some function: 'JR' - jsonrpc. Example: 'update JR'") + console.AddItem("plsc", inject_globals(PrintLiteServerConfig), "Print LiteServer config") + console.AddItem("clcf", inject_globals(CreateLocalConfigFile), "CreateLocalConfigFile") + console.AddItem("drvcf", inject_globals(DRVCF), "Dangerous recovery validator config file") + console.AddItem("setwebpass", inject_globals(SetWebPassword), "Set a password for the web admin interface") + + Refresh(local) +#end define + + +def Refresh(local): + user = local.buffer.user + local.buffer.mconfig_path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) + if user == 'root': + local.buffer.mconfig_path = "/usr/local/bin/mytoncore/mytoncore.db" + #end if + + # create variables + bin_dir = "/usr/bin/" + src_dir = "/usr/src/" + ton_work_dir = "/var/ton-work/" + ton_bin_dir = bin_dir + "ton/" + ton_src_dir = src_dir + "ton/" + local.buffer.bin_dir = bin_dir + local.buffer.src_dir = src_dir + local.buffer.ton_work_dir = ton_work_dir + local.buffer.ton_bin_dir = ton_bin_dir + local.buffer.ton_src_dir = ton_src_dir + ton_db_dir = ton_work_dir + "db/" + keys_dir = ton_work_dir + "keys/" + local.buffer.ton_db_dir = ton_db_dir + local.buffer.keys_dir = keys_dir + local.buffer.ton_log_path = ton_work_dir + "log" + local.buffer.validator_app_path = ton_bin_dir + "validator-engine/validator-engine" + local.buffer.global_config_path = ton_bin_dir + "global.config.json" + local.buffer.vconfig_path = ton_db_dir + "config.json" +#end define + + +def Status(local, args): + keys_dir = local.buffer.keys_dir + server_key = keys_dir + "server" + client_key = keys_dir + "client" + liteserver_key = keys_dir + "liteserver" + liteserver_pubkey = liteserver_key + ".pub" + + + fnStatus = os.path.isfile(local.buffer.vconfig_path) + mtcStatus = os.path.isfile(local.buffer.mconfig_path) + vcStatus = os.path.isfile(server_key) or os.path.isfile(client_key) + lsStatus = os.path.isfile(liteserver_pubkey) + + print("Full node status:", fnStatus) + print("Mytoncore status:", mtcStatus) + print("V.console status:", vcStatus) + print("Liteserver status:", lsStatus) +#end define + + +def Enable(local, args): + name = args[0] + if name == "PT": + CreateLocalConfigFile(local, args) + args = ["python3", "-m", "mytoninstaller", "-u", local.buffer.user, "-e", "enable{name}".format(name=name)] + run_as_root(args) +#end define + + +def DRVCF(local, args): + user = local.buffer["user"] + args = ["python3", "-m", "mytoninstaller", "-u", local.buffer.user, "-e", "drvcf"] + run_as_root(args) +#end define + + +def SetWebPassword(args): + args = ["python3", "/usr/src/mtc-jsonrpc/mtc-jsonrpc.py", "-p"] + subprocess.run(args) +#end define + + +def PrintLiteServerConfig(local, args): + liteServerConfig = GetLiteServerConfig(local) + text = json.dumps(liteServerConfig, indent=4) + print(text) +#end define + + +def CreateLocalConfigFile(local, args): + initBlock = GetInitBlock() + initBlock_b64 = dict2b64(initBlock) + user = local.buffer["user"] + args = ["python3", "-m", "mytoninstaller", "-u", local.buffer.user, "-e", "clc", "-i", initBlock_b64] + run_as_root(args) +#end define + + +def Event(local, name): + if name == "enableFN": + FirstNodeSettings(local) + if name == "enableVC": + EnableValidatorConsole(local) + if name == "enableLS": + EnableLiteServer(local) + if name == "enableDS": + EnableDhtServer(local) + if name == "drvcf": + DangerousRecoveryValidatorConfigFile(local) + if name == "enableJR": + EnableJsonRpc(local) + if name == "enablePT": + # EnablePytonv3(local) + EnableTonHttpApi(local) + if name == "clc": + ix = sys.argv.index("-i") + initBlock_b64 = sys.argv[ix+1] + initBlock = b642dict(initBlock_b64) + CreateLocalConfig(local, initBlock) +#end define + + +def General(local): + if "-u" in sys.argv: + ux = sys.argv.index("-u") + user = sys.argv[ux+1] + local.buffer.user = user + Refresh(local) + if "-e" in sys.argv: + ex = sys.argv.index("-e") + name = sys.argv[ex+1] + Event(local, name) + if "-m" in sys.argv: + mx = sys.argv.index("-m") + mode = sys.argv[mx+1] + if "-t" in sys.argv: + mx = sys.argv.index("-t") + telemetry = sys.argv[mx+1] + local.buffer.telemetry = str2bool(telemetry) + if "--dump" in sys.argv: + mx = sys.argv.index("--dump") + dump = sys.argv[mx+1] + local.buffer.dump = str2bool(dump) + #end if + + # Создать настройки для mytoncore.py + FirstMytoncoreSettings(local) + + if mode == "full": + FirstNodeSettings(local) + EnableValidatorConsole(local) + EnableLiteServer(local) + BackupVconfig(local) + BackupMconfig(local) + #end if + + # Создать символические ссылки + CreateSymlinks(local) + #end if +#end define + + +### +### Start of the program +### +def mytoninstaller(): + local = MyPyClass(__file__) + console = MyPyConsole() + + Init(local, console) + if len(sys.argv) > 1: + General(local) + else: + console.Run() + local.exit() diff --git a/mytoninstaller/scripts/__init__.py b/mytoninstaller/scripts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mytoninstaller/scripts/add2systemd.sh b/mytoninstaller/scripts/add2systemd.sh new file mode 100755 index 00000000..13626522 --- /dev/null +++ b/mytoninstaller/scripts/add2systemd.sh @@ -0,0 +1,62 @@ +#!/bin/bash +set -e + +# Проверить sudo +if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 +fi + +post="/bin/echo service down" +user=root +group=root + +while getopts n:s:p:u:g: flag +do + case "${flag}" in + n) name=${OPTARG};; + s) start=${OPTARG};; + p) post=${OPTARG};; + u) user=${OPTARG};; + g) group=${OPTARG};; + esac +done + +if [ -z "$name" ]; then + echo "name is empty" + exit 1 +fi + +if [ -z "$start" ]; then + echo "start is empty" + exit 1 +fi + + +DAEMON_PATH="/etc/systemd/system/${name}.service" + +cat < $DAEMON_PATH +[Unit] +Description = $name service. Created by https://github.com/igroman787/mypylib. +After = network.target + +[Service] +Type = simple +Restart = always +RestartSec = 30 +ExecStart = $start +ExecStopPost = $post +User = $user +Group = $group +LimitNOFILE = infinity +LimitNPROC = infinity +LimitMEMLOCK = infinity + +[Install] +WantedBy = multi-user.target +EOF + +chmod 664 $DAEMON_PATH +chmod +x $DAEMON_PATH +systemctl daemon-reload +systemctl enable ${name} diff --git a/scripts/jsonrpcinstaller.sh b/mytoninstaller/scripts/jsonrpcinstaller.sh old mode 100644 new mode 100755 similarity index 62% rename from scripts/jsonrpcinstaller.sh rename to mytoninstaller/scripts/jsonrpcinstaller.sh index a401eca3..e6338480 --- a/scripts/jsonrpcinstaller.sh +++ b/mytoninstaller/scripts/jsonrpcinstaller.sh @@ -15,6 +15,13 @@ do esac done +author=kdimentionaltree +repo=mtc-jsonrpc +branch=master + +echo "User: $user" +echo "Workdir: `pwd`" + # Цвета COLOR='\033[95m' ENDC='\033[0m' @@ -25,14 +32,17 @@ pip3 install Werkzeug json-rpc cloudscraper pyotp # Клонирование репозиториев с github.com echo -e "${COLOR}[2/4]${ENDC} Cloning github repository" +echo "https://github.com/${author}/${repo}.git -> ${branch}" + cd /usr/src/ rm -rf mtc-jsonrpc -git clone --recursive https://github.com/igroman787/mtc-jsonrpc.git +git clone --branch=${branch} --recursive https://github.com/${author}/${repo}.git # Прописать автозагрузку echo -e "${COLOR}[3/4]${ENDC} Add to startup" -cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import *; Add2Systemd(name='mtc-jsonrpc', user='${user}', start='/usr/bin/python3 /usr/src/mtc-jsonrpc/mtc-jsonrpc.py')" -python3 -c "${cmd}" +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +echo "Script dir: ${SCRIPT_DIR}" +${SCRIPT_DIR}/add2systemd.sh -n mtc-jsonrpc -s "/usr/bin/python3 /usr/src/mtc-jsonrpc/mtc-jsonrpc.py" -u ${user} -g ${user} systemctl restart mtc-jsonrpc # Выход из программы diff --git a/scripts/pytonv3installer.sh b/mytoninstaller/scripts/pytonv3installer.sh old mode 100644 new mode 100755 similarity index 76% rename from scripts/pytonv3installer.sh rename to mytoninstaller/scripts/pytonv3installer.sh index 0eb8d730..32010a4c --- a/scripts/pytonv3installer.sh +++ b/mytoninstaller/scripts/pytonv3installer.sh @@ -39,8 +39,9 @@ cd /usr/bin/ton && make tonlibjson # Прописать автозагрузку echo -e "${COLOR}[3/4]${ENDC} Add to startup" -cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import *; Add2Systemd(name='pytonv3', user='${user}', workdir='/usr/src/pytonv3', start='/usr/bin/python3 -m pyTON --liteserverconfig /usr/bin/ton/local.config.json --libtonlibjson /usr/bin/ton/tonlib/libtonlibjson.so')" -python3 -c "${cmd}" +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +echo "Script dir: ${SCRIPT_DIR}" +${SCRIPT_DIR}/add2systemd -n pytonv3 -s "/usr/bin/python3 -m pyTON --liteserverconfig /usr/bin/ton/local.config.json --libtonlibjson /usr/bin/ton/tonlib/libtonlibjson.so" -u ${user} -g ${user} systemctl restart pytonv3 # Конец diff --git a/mytoninstaller/scripts/tonhttpapiinstaller.sh b/mytoninstaller/scripts/tonhttpapiinstaller.sh new file mode 100755 index 00000000..c22b98e0 --- /dev/null +++ b/mytoninstaller/scripts/tonhttpapiinstaller.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +# Проверить sudo +if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 +fi + +# Get arguments +while getopts u: flag +do + case "${flag}" in + u) user=${OPTARG};; + esac +done + +# Цвета +COLOR='\033[92m' +ENDC='\033[0m' + +# Установка компонентов python3 +echo -e "${COLOR}[1/3]${ENDC} Installing required packages" +pip3 install -U ton-http-api + +# Установка модуля +echo -e "${COLOR}[2/3]${ENDC} Add to startup" +mkdir -p /var/ton-http-api/ton_keystore/ +chown -R $user /var/ton-http-api/ + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +cmd="ton-http-api --port=8000 --logs-level=INFO --cdll-path=/usr/bin/ton/tonlib/libtonlibjson.so --liteserver-config /usr/bin/ton/local.config.json --tonlib-keystore=/var/ton-http-api/ton_keystore/ --parallel-requests-per-liteserver=1024" +${SCRIPT_DIR}/add2systemd.sh -n ton-http-api -s "${cmd}" -u ${user} -g ${user} +systemctl restart ton-http-api + +# Конец +echo -e "${COLOR}[3/3]${ENDC} TonHttpApi installation complete" +exit 0 diff --git a/mytoninstaller.py b/mytoninstaller/settings.py similarity index 61% rename from mytoninstaller.py rename to mytoninstaller/settings.py index 25f53d93..df75edc3 100644 --- a/mytoninstaller.py +++ b/mytoninstaller/settings.py @@ -1,249 +1,26 @@ -#!/usr/bin/env python3 -# -*- coding: utf_8 -*- - -import pwd -import random +import os +import os.path +import psutil +import subprocess import requests -from mypylib.mypylib import * -from mypyconsole.mypyconsole import * - -local = MyPyClass(__file__) -console = MyPyConsole() -defaultLocalConfigPath = "/usr/bin/ton/local.config.json" - - -def Init(): - local.db.config.isStartOnlyOneProcess = False - local.db.config.logLevel = "debug" - local.db.config.isIgnorLogWarning = True # disable warning - local.run() - local.db.config.isIgnorLogWarning = False # enable warning - - - # create variables - user = os.environ.get("USER", "root") - local.buffer.user = user - local.buffer.vuser = "validator" - local.buffer.cport = random.randint(2000, 65000) - local.buffer.lport = random.randint(2000, 65000) - - # Create user console - console.name = "MyTonInstaller" - console.color = console.RED - console.AddItem("status", Status, "Print TON component status") - console.AddItem("enable", Enable, "Enable some function: 'FN' - Full node, 'VC' - Validator console, 'LS' - Liteserver, 'DS' - DHT-Server, 'JR' - jsonrpc, 'PT' - pyTONv3. Example: 'enable FN'") - console.AddItem("update", Enable, "Update some function: 'JR' - jsonrpc. Example: 'update JR'") - console.AddItem("plsc", PrintLiteServerConfig, "Print LiteServer config") - console.AddItem("clcf", CreateLocalConfigFile, "CreateLocalConfigFile") - console.AddItem("drvcf", DRVCF, "Dangerous recovery validator config file") - console.AddItem("setwebpass", SetWebPassword, "Set a password for the web admin interface") - - Refresh() -#end define - -def Refresh(): - user = local.buffer.user - local.buffer.mconfig_path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) - if user == 'root': - local.buffer.mconfig_path = "/usr/local/bin/mytoncore/mytoncore.db" - #end if - - # create variables - bin_dir = "/usr/bin/" - src_dir = "/usr/src/" - ton_work_dir = "/var/ton-work/" - ton_bin_dir = bin_dir + "ton/" - ton_src_dir = src_dir + "ton/" - local.buffer.bin_dir = bin_dir - local.buffer.src_dir = src_dir - local.buffer.ton_work_dir = ton_work_dir - local.buffer.ton_bin_dir = ton_bin_dir - local.buffer.ton_src_dir = ton_src_dir - ton_db_dir = ton_work_dir + "db/" - keys_dir = ton_work_dir + "keys/" - local.buffer.ton_db_dir = ton_db_dir - local.buffer.keys_dir = keys_dir - local.buffer.ton_log_path = ton_work_dir + "log" - local.buffer.validator_app_path = ton_bin_dir + "validator-engine/validator-engine" - local.buffer.global_config_path = ton_bin_dir + "global.config.json" - local.buffer.vconfig_path = ton_db_dir + "config.json" -#end define - -def Status(args): - keys_dir = local.buffer.keys_dir - server_key = keys_dir + "server" - client_key = keys_dir + "client" - liteserver_key = keys_dir + "liteserver" - liteserver_pubkey = liteserver_key + ".pub" - - - fnStatus = os.path.isfile(local.buffer.vconfig_path) - mtcStatus = os.path.isfile(local.buffer.mconfig_path) - vcStatus = os.path.isfile(server_key) or os.path.isfile(client_key) - lsStatus = os.path.isfile(liteserver_pubkey) - - print("Full node status:", fnStatus) - print("Mytoncore status:", mtcStatus) - print("V.console status:", vcStatus) - print("Liteserver status:", lsStatus) -#end define - -def Enable(args): - name = args[0] - if name == "PT": - CreateLocalConfigFile(args) - args = ["python3", local.buffer.my_path, "-u", local.buffer.user, "-e", "enable{name}".format(name=name)] - run_as_root(args) -#end define - -def DRVCF(args): - args = ["python3", local.buffer.my_path, "-u", local.buffer.user, "-e", "drvcf"] - run_as_root(args) -#end define - -def get_own_ip(): - requests.packages.urllib3.util.connection.HAS_IPV6 = False - ip = requests.get("https://ifconfig.me/ip").text - return ip -#end define - -def GetLiteServerConfig(): - keys_dir = local.buffer.keys_dir - liteserver_key = keys_dir + "liteserver" - liteserver_pubkey = liteserver_key + ".pub" - result = Dict() - file = open(liteserver_pubkey, 'rb') - data = file.read() - file.close() - key = base64.b64encode(data[4:]) - ip = get_own_ip() - mconfig = GetConfig(path=local.buffer.mconfig_path) - result.ip = ip2int(ip) - result.port = mconfig.liteClient.liteServer.port - result.id = Dict() - result.id["@type"]= "pub.ed25519" - result.id.key= key.decode() - return result -#end define - -def GetInitBlock(): - from mytoncore import MyTonCore - ton = MyTonCore() - initBlock = ton.GetInitBlock() - return initBlock -#end define - -def CreateLocalConfig(initBlock, localConfigPath=defaultLocalConfigPath): - # dirty hack, but GetInitBlock() function uses the same technique - from mytoncore import hex2base64 - - # read global config file - file = open("/usr/bin/ton/global.config.json", 'rt') - text = file.read() - data = json.loads(text) - file.close() - - # edit config - liteServerConfig = GetLiteServerConfig() - data["liteservers"] = [liteServerConfig] - data["validator"]["init_block"]["seqno"] = initBlock["seqno"] - data["validator"]["init_block"]["root_hash"] = hex2base64(initBlock["rootHash"]) - data["validator"]["init_block"]["file_hash"] = hex2base64(initBlock["fileHash"]) - text = json.dumps(data, indent=4) - - # write local config file - file = open(localConfigPath, 'wt') - file.write(text) - file.close() - - # chown - user = local.buffer.user - args = ["chown", "-R", user + ':' + user, localConfigPath] - - print("Local config file created:", localConfigPath) -#end define - -def PrintLiteServerConfig(args): - liteServerConfig = GetLiteServerConfig() - text = json.dumps(liteServerConfig, indent=4) - print(text) -#end define - -def CreateLocalConfigFile(args): - initBlock = GetInitBlock() - initBlock_b64 = dict2b64(initBlock) - args = ["python3", local.buffer.my_path, "-u", local.buffer.user, "-e", "clc", "-i", initBlock_b64] - run_as_root(args) -#end define - -def Event(name): - if name == "enableFN": - FirstNodeSettings() - if name == "enableVC": - EnableValidatorConsole() - if name == "enableLS": - EnableLiteServer() - if name == "enableDS": - EnableDhtServer() - if name == "drvcf": - DangerousRecoveryValidatorConfigFile() - if name == "enableJR": - EnableJsonRpc() - if name == "enablePT": - EnablePytonv3() - if name == "clc": - ix = sys.argv.index("-i") - initBlock_b64 = sys.argv[ix+1] - initBlock = b642dict(initBlock_b64) - CreateLocalConfig(initBlock) -#end define - -def General(): - if "-u" in sys.argv: - ux = sys.argv.index("-u") - user = sys.argv[ux+1] - local.buffer.user = user - Refresh() - if "-e" in sys.argv: - ex = sys.argv.index("-e") - name = sys.argv[ex+1] - Event(name) - if "-m" in sys.argv: - mx = sys.argv.index("-m") - mode = sys.argv[mx+1] - if "-t" in sys.argv: - mx = sys.argv.index("-t") - telemetry = sys.argv[mx+1] - local.buffer.telemetry = Str2Bool(telemetry) - if "--dump" in sys.argv: - mx = sys.argv.index("--dump") - dump = sys.argv[mx+1] - local.buffer.dump = Str2Bool(dump) - #end if - - # Создать настройки для mytoncore.py - FirstMytoncoreSettings() - - if mode == "full": - FirstNodeSettings() - EnableValidatorConsole() - EnableLiteServer() - BackupVconfig() - BackupMconfig() - #end if - - # Создать символические ссылки - CreateSymlinks() - #end if -#end define - -def Str2Bool(str): - if str == "true": - return True - return False -#end define - -def FirstNodeSettings(): +import random +import json +import pkg_resources + +from mypylib.mypylib import ( + add2systemd, + get_dir_from_path, + run_as_root, + color_print, + ip2int, + Dict +) +from mytoninstaller.utils import StartValidator, StartMytoncore +from mytoninstaller.config import SetConfig, GetConfig, get_own_ip +from mytoncore.utils import hex2b64 + + +def FirstNodeSettings(local): local.add_log("start FirstNodeSettings fuction", "debug") # Создать переменные @@ -259,7 +36,7 @@ def FirstNodeSettings(): # Проверить конфигурацию if os.path.isfile(vconfig_path): - local.add_log("Validators config.json already exist. Break FirstNodeSettings fuction", "warning") + local.add_log(f"Validators config '{vconfig_path}' already exist. Break FirstNodeSettings fuction", "warning") return #end if @@ -295,7 +72,7 @@ def FirstNodeSettings(): subprocess.run(args) # Скачать дамп - DownloadDump() + DownloadDump(local) # chown 1 local.add_log("Chown ton-work dir", "debug") @@ -303,10 +80,11 @@ def FirstNodeSettings(): subprocess.run(args) # start validator - StartValidator() + StartValidator(local) #end define -def DownloadDump(): + +def DownloadDump(local): dump = local.buffer.dump if dump == False: return @@ -331,18 +109,25 @@ def DownloadDump(): os.system(cmd) #end define -def FirstMytoncoreSettings(): + +def FirstMytoncoreSettings(local): local.add_log("start FirstMytoncoreSettings fuction", "debug") user = local.buffer.user # Прописать mytoncore.py в автозагрузку - add2systemd(name="mytoncore", user=user, start="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py") + # add2systemd(name="mytoncore", user=user, start="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py") # TODO: fix path + add2systemd(name="mytoncore", user=user, start="/usr/bin/python3 -m mytoncore") # Проверить конфигурацию path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) + if os.path.isfile(path): + local.add_log(f"{path} already exist. Break FirstMytoncoreSettings fuction", "warning") + return + #end if + path2 = "/usr/local/bin/mytoncore/mytoncore.db" - if os.path.isfile(path) or os.path.isfile(path2): - local.add_log("mytoncore.db already exist. Break FirstMytoncoreSettings fuction", "warning") + if os.path.isfile(path2): + local.add_log(f"{path2}.db already exist. Break FirstMytoncoreSettings fuction", "warning") return #end if @@ -395,10 +180,10 @@ def FirstMytoncoreSettings(): subprocess.run(args) # start mytoncore - StartMytoncore() + StartMytoncore(local) #end define -def EnableValidatorConsole(): +def EnableValidatorConsole(local): local.add_log("start EnableValidatorConsole function", "debug") # Create variables @@ -417,8 +202,13 @@ def EnableValidatorConsole(): server_pubkey = server_key + ".pub" # Check if key exist - if os.path.isfile(server_key) or os.path.isfile(client_key): - local.add_log("Server or client key already exist. Break EnableValidatorConsole fuction", "warning") + if os.path.isfile(server_key): + local.add_log(f"Server key '{server_key}' already exist. Break EnableValidatorConsole fuction", "warning") + return + #end if + + if os.path.isfile(client_key): + local.add_log(f"Client key '{client_key}' already exist. Break EnableValidatorConsole fuction", "warning") return #end if @@ -468,7 +258,7 @@ def EnableValidatorConsole(): SetConfig(path=vconfig_path, data=vconfig) # restart validator - StartValidator() + StartValidator(local) # read mconfig mconfig_path = local.buffer.mconfig_path @@ -486,15 +276,16 @@ def EnableValidatorConsole(): SetConfig(path=mconfig_path, data=mconfig) # Подтянуть событие в mytoncore.py - cmd = "python3 {src_dir}mytonctrl/mytoncore.py -e \"enableVC\"".format(src_dir=src_dir) + # cmd = "python3 {srcDir}mytonctrl/mytoncore.py -e \"enableVC\"".format(srcDir=srcDir) + cmd = 'python3 -m mytoncore -e "enableVC"' args = ["su", "-l", user, "-c", cmd] subprocess.run(args) # restart mytoncore - StartMytoncore() + StartMytoncore(local) #end define -def EnableLiteServer(): +def EnableLiteServer(local): local.add_log("start EnableLiteServer function", "debug") # Create variables @@ -512,7 +303,7 @@ def EnableLiteServer(): # Check if key exist if os.path.isfile(liteserver_pubkey): - local.add_log("Liteserver key already exist. Break EnableLiteServer fuction", "warning") + local.add_log(f"Liteserver key '{liteserver_pubkey}' already exist. Break EnableLiteServer fuction", "warning") return #end if @@ -557,7 +348,7 @@ def EnableLiteServer(): SetConfig(path=vconfig_path, data=vconfig) # restart validator - StartValidator() + StartValidator(local) # edit mytoncore config file # read mconfig @@ -578,89 +369,114 @@ def EnableLiteServer(): SetConfig(path=mconfig_path, data=mconfig) # restart mytoncore - StartMytoncore() + StartMytoncore(local) #end define -def StartValidator(): - # restart validator - local.add_log("Start/restart validator service", "debug") - args = ["systemctl", "restart", "validator"] - subprocess.run(args) - # sleep 10 sec - local.add_log("sleep 10 sec", "debug") - time.sleep(10) -#end define +def EnableDhtServer(local): + local.add_log("start EnableDhtServer function", "debug") + vuser = local.buffer.vuser + ton_bin_dir = local.buffer.ton_bin_dir + globalConfigPath = local.buffer.global_config_path + dht_server = ton_bin_dir + "dht-server/dht-server" + generate_random_id = ton_bin_dir + "utils/generate-random-id" + tonDhtServerDir = "/var/ton-dht-server/" + tonDhtKeyringDir = tonDhtServerDir + "keyring/" -def StartMytoncore(): - # restart mytoncore - local.add_log("Start/restart mytoncore service", "debug") - args = ["systemctl", "restart", "mytoncore"] - subprocess.run(args) -#end define + # Проверить конфигурацию + dht_config_path = "/var/ton-dht-server/config.json" + if os.path.isfile(dht_config_path): + local.add_log(f"DHT-Server '{dht_config_path}' already exist. Break EnableDhtServer fuction", "warning") + return + #end if -def GetConfig(**kwargs): - path = kwargs.get("path") - file = open(path, 'rt') - text = file.read() - file.close() - config = Dict(json.loads(text)) - return config -#end define + # Подготовить папку + os.makedirs(tonDhtServerDir, exist_ok=True) -def SetConfig(**kwargs): - path = kwargs.get("path") - data = kwargs.get("data") + # Прописать автозагрузку + cmd = "{dht_server} -C {globalConfigPath} -D {tonDhtServerDir}" + cmd = cmd.format(dht_server=dht_server, globalConfigPath=globalConfigPath, tonDhtServerDir=tonDhtServerDir) + add2systemd(name="dht-server", user=vuser, start=cmd) - # write config + # Получить внешний ip адрес + ip = get_own_ip() + port = random.randint(2000, 65000) + addr = "{ip}:{port}".format(ip=ip, port=port) + + # Первый запуск + args = [dht_server, "-C", globalConfigPath, "-D", tonDhtServerDir, "-I", addr] + subprocess.run(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + # Получить вывод конфига + key = os.listdir(tonDhtKeyringDir)[0] + ip = ip2int(ip) + text = '{"@type": "adnl.addressList", "addrs": [{"@type": "adnl.address.udp", "ip": ' + str(ip) + ', "port": ' + str(port) + '}], "version": 0, "reinit_date": 0, "priority": 0, "expire_at": 0}' + args = [generate_random_id, "-m", "dht", "-k", tonDhtKeyringDir + key, "-a", text] + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + output = process.stdout.decode("utf-8") + err = process.stderr.decode("utf-8") + if len(err) > 0: + raise Exception(err) + #end if + + data = json.loads(output) text = json.dumps(data, indent=4) - file = open(path, 'wt') - file.write(text) - file.close() -#end define + print(text) -def BackupVconfig(): - local.add_log("Backup validator config file 'config.json' to 'config.json.backup'", "debug") - vconfig_path = local.buffer.vconfig_path - backupPath = vconfig_path + ".backup" - args = ["cp", vconfig_path, backupPath] + # chown 1 + args = ["chown", "-R", vuser + ':' + vuser, tonDhtServerDir] subprocess.run(args) -#end define -def BackupMconfig(): - local.add_log("Backup mytoncore config file 'mytoncore.db' to 'mytoncore.db.backup'", "debug") - mconfig_path = local.buffer.mconfig_path - backupPath = mconfig_path + ".backup" - args = ["cp", mconfig_path, backupPath] + # start DHT-Server + args = ["systemctl", "restart", "dht-server"] subprocess.run(args) #end define -def GetPortsFromVconfig(): - vconfig_path = local.buffer.vconfig_path - # read vconfig - local.add_log("read vconfig", "debug") - vconfig = GetConfig(path=vconfig_path) +def EnableJsonRpc(local): + local.add_log("start EnableJsonRpc function", "debug") + user = local.buffer.user - # read mconfig - local.add_log("read mconfig", "debug") - mconfig_path = local.buffer.mconfig_path - mconfig = GetConfig(path=mconfig_path) + jsonrpcinstaller_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'jsonrpcinstaller.sh') + local.add_log(f"Running script: {jsonrpcinstaller_path}", "debug") + exitCode = run_as_root(["bash", jsonrpcinstaller_path, "-u", user]) # TODO: fix path + if exitCode == 0: + text = "EnableJsonRpc - {green}OK{endc}" + else: + text = "EnableJsonRpc - {red}Error{endc}" + color_print(text) +#end define - # edit mytoncore config file - local.add_log("edit mytoncore config file", "debug") - mconfig.liteClient.liteServer.port = mconfig.liteservers[0].port - mconfig.validatorConsole.addr = f"127.0.0.1:{mconfig.control[0].port}" - # write mconfig - local.add_log("write mconfig", "debug") - SetConfig(path=mconfig_path, data=mconfig) +def EnablePytonv3(local): + local.add_log("start EnablePytonv3 function", "debug") + user = local.buffer.user - # restart mytoncore - StartMytoncore() + pythonv3installer_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'pytonv3installer.sh') + local.add_log(f"Running script: {pythonv3installer_path}", "debug") + exitCode = run_as_root(["bash", pythonv3installer_path, "-u", user]) + if exitCode == 0: + text = "EnablePytonv3 - {green}OK{endc}" + else: + text = "EnablePytonv3 - {red}Error{endc}" + color_print(text) #end define -def DangerousRecoveryValidatorConfigFile(): + +def EnableTonHttpApi(local): + local.add_log("start EnablePytonv3 function", "debug") + user = local.buffer.user + + ton_http_api_installer_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'tonhttpapiinstaller.sh') + exitCode = run_as_root(["bash", ton_http_api_installer_path, "-u", user]) + if exitCode == 0: + text = "EnableTonHttpApi - {green}OK{endc}" + else: + text = "EnableTonHttpApi - {red}Error{endc}" + color_print(text) + + +def DangerousRecoveryValidatorConfigFile(local): local.add_log("start DangerousRecoveryValidatorConfigFile function", "info") # install and import cryptography library @@ -865,21 +681,8 @@ def DangerousRecoveryValidatorConfigFile(): print("keys:", keys) #end define -def hex2b64(input): - hexBytes = bytes.fromhex(input) - b64Bytes = base64.b64encode(hexBytes) - b64String = b64Bytes.decode() - return b64String -#end define -def b642hex(input): - b64Bytes = input.encode() - hexBytes = base64.b64decode(b64Bytes) - hexString = hexBytes.hex() - return hexString -#end define - -def CreateSymlinks(): +def CreateSymlinks(local): local.add_log("start CreateSymlinks fuction", "debug") cport = local.buffer.cport @@ -889,7 +692,8 @@ def CreateSymlinks(): validator_console_file = "/usr/bin/validator-console" env_file = "/etc/environment" file = open(mytonctrl_file, 'wt') - file.write("/usr/bin/python3 /usr/src/mytonctrl/mytonctrl.py $@") + # file.write("/usr/bin/python3 /usr/src/mytonctrl/mytonctrl.py $@") # TODO: fix path + file.write("/usr/bin/python3 -m mytonctrl $@") # TODO: fix path file.close() file = open(fift_file, 'wt') file.write("/usr/bin/ton/crypto/fift $@") @@ -914,129 +718,3 @@ def CreateSymlinks(): file.write(fiftpath + '\n') file.close() #end define - -def EnableDhtServer(): - local.add_log("start EnableDhtServer function", "debug") - vuser = local.buffer.vuser - ton_bin_dir = local.buffer.ton_bin_dir - globalConfigPath = local.buffer.global_config_path - dht_server = ton_bin_dir + "dht-server/dht-server" - generate_random_id = ton_bin_dir + "utils/generate-random-id" - tonDhtServerDir = "/var/ton-dht-server/" - tonDhtKeyringDir = tonDhtServerDir + "keyring/" - - # Проверить конфигурацию - if os.path.isfile("/var/ton-dht-server/config.json"): - local.add_log("DHT-Server config.json already exist. Break EnableDhtServer fuction", "warning") - return - #end if - - # Подготовить папку - os.makedirs(tonDhtServerDir, exist_ok=True) - - # Прописать автозагрузку - cmd = "{dht_server} -C {globalConfigPath} -D {tonDhtServerDir}" - cmd = cmd.format(dht_server=dht_server, globalConfigPath=globalConfigPath, tonDhtServerDir=tonDhtServerDir) - add2systemd(name="dht-server", user=vuser, start=cmd) - - # Получить внешний ip адрес - ip = get_own_ip() - port = random.randint(2000, 65000) - addr = "{ip}:{port}".format(ip=ip, port=port) - - # Первый запуск - args = [dht_server, "-C", globalConfigPath, "-D", tonDhtServerDir, "-I", addr] - subprocess.run(args, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - - # Получить вывод конфига - key = os.listdir(tonDhtKeyringDir)[0] - ip = ip2int(ip) - text = '{"@type": "adnl.addressList", "addrs": [{"@type": "adnl.address.udp", "ip": ' + str(ip) + ', "port": ' + str(port) + '}], "version": 0, "reinit_date": 0, "priority": 0, "expire_at": 0}' - args = [generate_random_id, "-m", "dht", "-k", tonDhtKeyringDir + key, "-a", text] - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) - output = process.stdout.decode("utf-8") - err = process.stderr.decode("utf-8") - if len(err) > 0: - raise Exeption(err) - #end if - - data = json.loads(output) - text = json.dumps(data, indent=4) - print(text) - - # chown 1 - args = ["chown", "-R", vuser + ':' + vuser, tonDhtServerDir] - subprocess.run(args) - - # start DHT-Server - args = ["systemctl", "restart", "dht-server"] - subprocess.run(args) -#end define - -def SetWebPassword(args): - args = ["python3", "/usr/src/mtc-jsonrpc/mtc-jsonrpc.py", "-p"] - subprocess.run(args) -#end define - -def EnableJsonRpc(): - local.add_log("start EnableJsonRpc function", "debug") - user = local.buffer.user - exitCode = run_as_root(["bash", "/usr/src/mytonctrl/scripts/jsonrpcinstaller.sh", "-u", user]) - if exitCode == 0: - text = "EnableJsonRpc - {green}OK{endc}" - else: - text = "EnableJsonRpc - {red}Error{endc}" - color_print(text) -#end define - -def EnablePytonv3(): - local.add_log("start EnablePytonv3 function", "debug") - user = local.buffer.user - exitCode = run_as_root(["bash", "/usr/src/mytonctrl/scripts/pytonv3installer.sh", "-u", user]) - if exitCode == 0: - text = "EnablePytonv3 - {green}OK{endc}" - else: - text = "EnablePytonv3 - {red}Error{endc}" - color_print(text) -#end define - -def str2b64(s): - b = s.encode("utf-8") - b64 = base64.b64encode(b) - b64 = b64.decode("utf-8") - return b64 -#end define - -def b642str(b64): - b64 = b64.encode("utf-8") - b = base64.b64decode(b64) - s = b.decode("utf-8") - return s -#end define - -def dict2b64(d): - s = json.dumps(d) - b64 = str2b64(s) - return b64 -#end define - -def b642dict(b64): - s = b642str(b64) - d = json.loads(s) - return d -#end define - - - -### -### Start of the program -### - -if __name__ == "__main__": - Init() - if len(sys.argv) > 1: - General() - else: - console.Run() - local.exit() -#end if diff --git a/mytoninstaller/utils.py b/mytoninstaller/utils.py new file mode 100644 index 00000000..9b33b732 --- /dev/null +++ b/mytoninstaller/utils.py @@ -0,0 +1,33 @@ +import base64 +import json +import time +import subprocess + + +def GetInitBlock(): + from mytoncore import MyTonCore + + ton = MyTonCore(None) + initBlock = ton.GetInitBlock() + return initBlock +# end define + + +def StartValidator(local): + # restart validator + local.add_log("Start/restart validator service", "debug") + args = ["systemctl", "restart", "validator"] + subprocess.run(args) + + # sleep 10 sec + local.add_log("sleep 10 sec", "debug") + time.sleep(10) +# end define + + +def StartMytoncore(local): + # restart mytoncore + local.add_log("Start/restart mytoncore service", "debug") + args = ["systemctl", "restart", "mytoncore"] + subprocess.run(args) +# end define diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..bacf8a0e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +crc16 +requests +psutil +cryptography +fastcrc diff --git a/scripts/install.sh b/scripts/install.sh index 8f80eebb..5d6fc980 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,12 +1,21 @@ #!/bin/bash set -e -# Проверить sudo +# colors +COLOR='\033[92m' +ENDC='\033[0m' +mydir=`pwd` + +# check sudo permissions if [ "$(id -u)" != "0" ]; then - echo "Please run script as root" - exit 1 + echo "Please run script as root" + exit 1 fi +author="ton-blockchain" +repo="mytonctrl" +branch="master" + show_help_and_exit() { echo 'Supported argumets:' echo ' -m [lite|full] Choose installation mode' @@ -14,7 +23,10 @@ show_help_and_exit() { echo ' -t Disable telemetry' echo ' -i Ignore minimum reqiurements' echo ' -d Use pre-packaged dump. Reduces duration of initial synchronization.' - echo ' -h Show this help' + echo ' -a Set MyTonCtrl git repo author' + echo ' -r Set MyTonCtrl git repo' + echo ' -b Set MyTonCtrl git repo branch' + echo ' -h Show this help' exit } @@ -22,12 +34,14 @@ if [[ "${1-}" =~ ^-*h(elp)?$ ]]; then show_help_and_exit fi -# Get arguments +# node install parameters config="https://ton-blockchain.github.io/global.config.json" telemetry=true ignore=false dump=false -while getopts m:c:tidh flag + + +while getopts m:c:tida:r:b: flag do case "${flag}" in m) mode=${OPTARG};; @@ -35,23 +49,29 @@ do t) telemetry=false;; i) ignore=true;; d) dump=true;; - h) show_help_and_exit;; - *) + a) author=${OPTARG};; + r) repo=${OPTARG};; + b) branch=${OPTARG};; + h) show_help_and_exit;; + *) echo "Flag -${flag} is not recognized. Aborting" exit 1 ;; esac done - -# Проверка режима установки +# check installation mode if [ "${mode}" != "lite" ] && [ "${mode}" != "full" ]; then echo "Run script with flag '-m lite' or '-m full'" exit 1 fi -# Проверка мощностей +# check machine configuration +echo -e "${COLOR}[1/5]${ENDC} Checking system requirements" + cpus=$(lscpu | grep "CPU(s)" | head -n 1 | awk '{print $2}') -memory=$(grep MemTotal /proc/meminfo | awk '{print $2}') +memory=$(cat /proc/meminfo | grep MemTotal | awk '{print $2}') + +echo "This machine has ${cpus} CPUs and ${memory}KB of Memory" if [ "${mode}" = "lite" ] && [ "$ignore" = false ] && ([ "${cpus}" -lt 2 ] || [ "${memory}" -lt 2000000 ]); then echo "Insufficient resources. Requires a minimum of 2 processors and 2Gb RAM." exit 1 @@ -61,49 +81,53 @@ if [ "${mode}" = "full" ] && [ "$ignore" = false ] && ([ "${cpus}" -lt 8 ] || [ exit 1 fi -# Цвета -COLOR='\033[92m' -ENDC='\033[0m' - -# Начинаю установку mytonctrl -echo -e "${COLOR}[1/4]${ENDC} Starting installation MyTonCtrl" -mydir=$(pwd) - -# На OSX нет такой директории по-умолчанию, поэтому создаем... +echo -e "${COLOR}[2/5]${ENDC} Checking for required TON components" SOURCES_DIR=/usr/src BIN_DIR=/usr/bin + +# create dirs for OSX if [[ "$OSTYPE" =~ darwin.* ]]; then SOURCES_DIR=/usr/local/src BIN_DIR=/usr/local/bin mkdir -p ${SOURCES_DIR} fi -# Проверяю наличие компонентов TON -echo -e "${COLOR}[2/4]${ENDC} Checking for required TON components" +# check TON components file1=${BIN_DIR}/ton/crypto/fift file2=${BIN_DIR}/ton/lite-client/lite-client file3=${BIN_DIR}/ton/validator-engine-console/validator-engine-console -if [ -f "${file1}" ] && [ -f "${file2}" ] && [ -f "${file3}" ]; then - echo "TON exist" - cd $SOURCES_DIR - rm -rf $SOURCES_DIR/mytonctrl - git clone --recursive https://github.com/ton-blockchain/mytonctrl.git -else - rm -f toninstaller.sh - wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/toninstaller.sh - bash toninstaller.sh -c "${config}" - rm -f toninstaller.sh + +if [ ! -f "${file1}" ] || [ ! -f "${file2}" ] || [ ! -f "${file3}" ]; then + echo "TON does not exists, building" + wget https://raw.githubusercontent.com/${author}/${repo}/${branch}/scripts/ton_installer.sh -O /tmp/ton_installer.sh + bash /tmp/ton_installer.sh -c ${config} fi -# Запускаю установщик mytoninstaller.py -echo -e "${COLOR}[3/4]${ENDC} Launching the mytoninstaller.py" +# Cloning mytonctrl +echo -e "${COLOR}[3/5]${ENDC} Installing MyTonCtrl" +echo "https://github.com/${author}/${repo}.git -> ${branch}" + +cd $SOURCES_DIR +rm -rf $SOURCES_DIR/mytonctrl + +git clone https://github.com/${author}/${repo}.git ${repo} # TODO: return --recursive back when fix libraries +cd $SOURCES_DIR/${repo} +git checkout ${branch} +git submodule update --init --recursive +git config --global --add safe.directory $SOURCES_DIR/${repo} + +pip3 install -U . # TODO: make installation from git directly + +echo -e "${COLOR}[3/5]${ENDC} Running myton.installer" +# DEBUG + parent_name=$(ps -p $PPID -o comm=) user=$(whoami) if [ "$parent_name" = "sudo" ] || [ "$parent_name" = "su" ]; then user=$(logname) fi -python3 ${SOURCES_DIR}/mytonctrl/mytoninstaller.py -m ${mode} -u ${user} -t ${telemetry} --dump ${dump} +echo "User: $user" +python3 -m mytoninstaller -m ${mode} -u ${user} -t ${telemetry} --dump ${dump} -# Выход из программы echo -e "${COLOR}[4/4]${ENDC} Mytonctrl installation completed" exit 0 diff --git a/scripts/toninstaller.sh b/scripts/ton_installer.sh old mode 100755 new mode 100644 similarity index 66% rename from scripts/toninstaller.sh rename to scripts/ton_installer.sh index 807036e9..8ebab9ad --- a/scripts/toninstaller.sh +++ b/scripts/ton_installer.sh @@ -1,3 +1,4 @@ + #!/bin/bash set -e @@ -8,7 +9,7 @@ if [ "$(id -u)" != "0" ]; then fi # Get arguments -config="https://ton-blockchain.github.io/global.config.json" +config=https://ton-blockchain.github.io/global.config.json while getopts c: flag do case "${flag}" in @@ -32,55 +33,20 @@ fi # Установка требуемых пакетов echo -e "${COLOR}[1/6]${ENDC} Installing required packages" if [ "$OSTYPE" == "linux-gnu" ]; then - - # Determine if it is a CentOS system - if cat /etc/*release | grep ^NAME | grep CentOS ; then - echo "CentOS Linux detected." - yum update -y + if [ hash yum 2>/dev/null ]; then + echo "RHEL-based Linux detected." yum install -y epel-release - yum install -y git gflags gflags-devel zlib zlib-devel openssl-devel openssl-libs readline-devel libmicrohttpd python3 python3-pip python36-devel g++ gcc libstdc++-devel zlib1g-dev libssl-dev which make gcc-c++ libstdc++-devel - - # Upgrade make and gcc in CentOS system - yum install centos-release-scl -y - yum install devtoolset-10 -y - echo "source /opt/rh/devtoolset-10/enable" >> /etc/bashrc - source /opt/rh/devtoolset-10/enable - - # Install the new version of CMake - yum remove cmake -y - wget https://cmake.org/files/v3.24/cmake-3.24.2.tar.gz - tar -zxvf cmake-3.24.2.tar.gz - cd cmake-3.24.2 && ./bootstrap && make -j -j$(nproc) && make install - yum remove cmake -y - ln -s /usr/local/bin/cmake /usr/bin/cmake - source ~/.bashrc - cmake --version - - # Install ninja - yum install -y ninja-build - - # Red Hat systems are not supported - elif cat /etc/*release | grep ^NAME | grep Red ; then - echo "Red Hat Linux detected." - echo "This OS is not supported with this script at present. Sorry." - echo "Please refer to https://github.com/ton-blockchain/mytonctrl for setup information." - exit 1 - - # Suse systems are not supported + dnf config-manager --set-enabled PowerTools + yum install -y git make cmake clang gflags gflags-devel zlib zlib-devel openssl-devel openssl-libs readline-devel libmicrohttpd python3 python3-pip python36-devel elif [ -f /etc/SuSE-release ]; then echo "Suse Linux detected." echo "This OS is not supported with this script at present. Sorry." echo "Please refer to https://github.com/ton-blockchain/mytonctrl for setup information." exit 1 - elif [ -f /etc/arch-release ]; then echo "Arch Linux detected." - pacman -Syuy --noconfirm - pacman -S --noconfirm git cmake clang gflags zlib openssl readline libmicrohttpd python python-pip - - # Install ninja - pacman -S --noconfirm ninja - + pacman -Syuy + pacman -S --noconfirm git make cmake clang gflags zlib openssl readline libmicrohttpd python python-pip elif [ -f /etc/debian_version ]; then echo "Ubuntu/Debian Linux detected." apt-get update @@ -95,8 +61,6 @@ if [ "$OSTYPE" == "linux-gnu" ]; then echo "Please refer to https://github.com/ton-blockchain/mytonctrl for setup information." exit 1 fi - -# Detected mac os system. elif [[ "$OSTYPE" =~ darwin.* ]]; then echo "Mac OS (Darwin) detected." if [ ! which brew >/dev/null 2>&1 ]; then @@ -108,34 +72,27 @@ elif [[ "$OSTYPE" =~ darwin.* ]]; then su $LOCAL_USERNAME -c "brew update" su $LOCAL_USERNAME -c "brew install openssl cmake llvm" - - # Install ninja - su $LOCAL_USERNAME -c "brew install ninja" - elif [ "$OSTYPE" == "freebsd"* ]; then echo "FreeBSD detected." echo "This OS is not supported with this script at present. Sorry." - echo "Please refer to https://github.com/paritytech/substrate for setup information." + echo "Please refer to https://github.com/paritytech/substrate for setup information." # TODO: remove links exit 1 else echo "Unknown operating system." echo "This OS is not supported with this script at present. Sorry." - echo "Please refer to https://github.com/paritytech/substrate for setup information." + echo "Please refer to https://github.com/paritytech/substrate for setup information." # TODO: remove links exit 1 fi # Установка компонентов python3 -pip3 install psutil fastcrc requests +pip3 install psutil crc16 requests # Клонирование репозиториев с github.com echo -e "${COLOR}[2/6]${ENDC} Cloning github repository" cd $SOURCES_DIR rm -rf $SOURCES_DIR/ton -rm -rf $SOURCES_DIR/mytonctrl git clone --recursive https://github.com/ton-blockchain/ton.git -git clone --recursive https://github.com/ton-blockchain/mytonctrl.git git config --global --add safe.directory $SOURCES_DIR/ton -git config --global --add safe.directory $SOURCES_DIR/mytonctrl # Подготавливаем папки для компиляции echo -e "${COLOR}[3/6]${ENDC} Preparing for compilation" @@ -158,12 +115,12 @@ fi if [[ "$OSTYPE" =~ darwin.* ]]; then if [[ $(uname -p) == 'arm' ]]; then echo M1 - CC="clang -mcpu=apple-a14" CXX="clang++ -mcpu=apple-a14" cmake $SOURCES_DIR/ton -DCMAKE_BUILD_TYPE=Release -DTON_ARCH= -Wno-dev -GNinja + CC="clang -mcpu=apple-a14" CXX="clang++ -mcpu=apple-a14" cmake $SOURCES_DIR/ton -DCMAKE_BUILD_TYPE=Release -DTON_ARCH= -Wno-dev else - cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja + cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton fi else - cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja + cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton fi # Компилируем из исходников @@ -180,7 +137,7 @@ else fi echo "use ${cpuNumber} cpus" -ninja -j ${cpuNumber} fift validator-engine lite-client validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy +make -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy # Скачиваем конфигурационные файлы lite-client echo -e "${COLOR}[5/6]${ENDC} Downloading config files" diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index 87ef4a6b..a86575cc 100644 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -1,4 +1,10 @@ #!/bin/bash +full=true +while getopts f flag; do + case "${flag}" in + f) full=false + esac +done # Проверить sudo if [ "$(id -u)" != "0" ]; then @@ -26,11 +32,17 @@ rm -rf /etc/systemd/system/dht-server.service systemctl daemon-reload # Удаление файлов -rm -rf /usr/src/ton +if $full; then + echo "removing Ton node" + rm -rf /usr/src/ton + rm -rf /usr/bin/ton + rm -rf /var/ton-work + rm -rf /var/ton-dht-server +fi + rm -rf /usr/src/mytonctrl -rm -rf /usr/bin/ton -rm -rf /var/ton-work -rm -rf /var/ton-dht-server +rm -rf /usr/src/mtc-jsonrpc +rm -rf /usr/src/pytonv3 rm -rf /tmp/myton* rm -rf /usr/local/bin/mytoninstaller/ rm -rf /usr/local/bin/mytoncore/mytoncore.db @@ -38,10 +50,17 @@ rm -rf /home/${user}/.local/share/mytonctrl rm -rf /home/${user}/.local/share/mytoncore/mytoncore.db # Удаление ссылок -rm -rf /usr/bin/fift -rm -rf /usr/bin/liteclient -rm -rf /usr/bin/validator-console +if $full; then + echo "removing ton node" + rm -rf /usr/bin/fift + rm -rf /usr/bin/liteclient + rm -rf /usr/bin/validator-console +fi rm -rf /usr/bin/mytonctrl +# removing pip packages +pip3 uninstall -y myton mypylib mypyconsole +pip3 uninstall -y ton-http-api + # Конец echo -e "${COLOR}Uninstall Complete${ENDC}" diff --git a/scripts/upgrade.py b/scripts/upgrade.py deleted file mode 100644 index 9971694a..00000000 --- a/scripts/upgrade.py +++ /dev/null @@ -1,31 +0,0 @@ -# Говнокод ON -import os -from sys import path -from os.path import dirname as dir -path.append(dir(path[0])) -# Говнокод OFF - -from mypylib.mypylib import * - - -# validator.service -file = open("/etc/systemd/system/validator.service", 'rt') -text = file.read() -file.close() -lines = text.split('\n') - -for i in range(len(lines)): - line = lines[i] - if "ExecStart" not in line: - continue - if "ton-global.config.json" in line: - lines[i] += line.replace("validator-engine/ton-global.config.json", "global.config.json") -#end for - -text = "\n".join(lines) -file = open("/etc/systemd/system/validator.service", 'wt') -file.write(text) -file.close() - -args = ["systemctl", "daemon-reload"] -subprocess.run(args) diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..b0b42415 --- /dev/null +++ b/setup.py @@ -0,0 +1,43 @@ +from setuptools import setup, find_packages +from os.path import dirname, join + +with open(join(dirname(__file__), "README.md"), "r") as f: + long_description = f.read() + + +version = 'dev' + +setup( + author='igroman', + author_email='igroman', + name='myton', + version=version, + packages=find_packages('.', exclude=['tests']), + install_requires=[ + 'crc16', + 'requests', + 'psutil', + 'cryptography', + 'fastcrc', + ], + package_data={ + 'mytoninstaller.scripts': ['*.sh'], + 'mytonctrl': ['resources/*', 'scripts/*.sh'], + '': ['requirements.txt'], + }, + zip_safe=True, + python_requires='>=3.7', + classifiers=[ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "License :: Other/Proprietary License", + "Topic :: Software Development :: Libraries" + ], + # url="https://github.com/toncenter/pytonlib", + description="MyTonCtrl", + long_description_content_type="text/markdown", + long_description=long_description, +) diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/blocksScanner.py b/tests/blocksScanner.py index b8296746..88b012ff 100644 --- a/tests/blocksScanner.py +++ b/tests/blocksScanner.py @@ -1,9 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*- -import sys -sys.path.append("/usr/src/mytonctrl/") -from mypylib.mypylib import bcolors, Sleep +from mypylib.mypylib import bcolors, Sleep, MyPyClass from mytoncore import MyTonCore, TonBlocksScanner def NewBlockReaction(block): @@ -19,7 +17,8 @@ def NewMessageReaction(message): #end define -ton = MyTonCore() +local = MyPyClass('./tests') +ton = MyTonCore(local) scanner = TonBlocksScanner(ton, nbr=NewBlockReaction, ntr=NewTransReaction, nmr=NewMessageReaction) scanner.Run() Sleep() diff --git a/tests/bounce.py b/tests/bounce.py index 79d60b32..08e5aa20 100644 --- a/tests/bounce.py +++ b/tests/bounce.py @@ -1,17 +1,18 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*-l -from sys import path -path.append("/usr/src/mytonctrl/") -from mytoncore import * +import time -Local = MyPyClass(__file__) -ton = MyTonCore() +from mypylib.mypylib import MyPyClass +from mytoncore import MyTonCore + +local = MyPyClass('./tests') +ton = MyTonCore(local) def Init(): wallets = list() - Local.buffer["wallets"] = wallets + local.buffer["wallets"] = wallets walletsNameList = ton.GetWalletsNameList() # Create tests wallet @@ -50,7 +51,7 @@ def Init(): buff_wallet = wallet buff_wallet.oldseqno = ton.GetSeqno(wallet) ton.MoveCoinsFromHW(wallet, [[testsWallet.addr, need]], wait=False) - Local.AddLog(testsWallet.name + " <<< " + str(wallet.subwallet)) + local.AddLog(testsWallet.name + " <<< " + str(wallet.subwallet)) if buff_wallet: ton.WaitTransaction(buff_wallet) #end for @@ -63,18 +64,18 @@ def Init(): if wallet.account.status == "uninit": wallet.oldseqno = ton.GetSeqno(wallet) ton.SendFile(wallet.bocFilePath) - Local.AddLog(str(wallet.subwallet) + " - OK") + local.AddLog(str(wallet.subwallet) + " - OK") ton.WaitTransaction(wallets[-1]) #end define def Work(): - wallets = Local.buffer["wallets"] + wallets = local.buffer["wallets"] destList = list() destList.append(["EQAY_2_A88HD43S96hbVGbCLB21e6_k1nbaqICwS3ZCrMBaZ", 2]) for wallet in wallets: wallet.oldseqno = ton.GetSeqno(wallet) ton.MoveCoinsFromHW(wallet, destList, wait=False) - Local.AddLog(str(wallet.subwallet) + " " + wallet.addr + " >>> ") + local.AddLog(str(wallet.subwallet) + " " + wallet.addr + " >>> ") ton.WaitTransaction(wallets[-1]) #end define @@ -83,7 +84,7 @@ def General(): while True: time.sleep(1) Work() - Local.AddLog("Work - OK") + local.AddLog("Work - OK") #end while #end define @@ -92,10 +93,10 @@ def General(): ### ### Start test ### -Local.Run() +local.Run() load = 200 -Local.StartCycle(General, sec=1) +local.StartCycle(General, sec=1) while True: time.sleep(60) #load += 10 diff --git a/tests/mg.py b/tests/mg.py index 536982b1..49877117 100644 --- a/tests/mg.py +++ b/tests/mg.py @@ -3,13 +3,13 @@ import sys import time -sys.path.append("/usr/src/mytonctrl/") + from mypylib.mypylib import bcolors, Sleep from mytoncore import MyTonCore from mypylib.mypylib import MyPyClass -ton = MyTonCore() local = MyPyClass(__file__) +ton = MyTonCore(local) def TestMoveCoins(wallet, dest, coins, **kwargs): start = time.time() diff --git a/tests/tpsLoad.py b/tests/tpsLoad.py index 8d44ae5c..3edb92dd 100644 --- a/tests/tpsLoad.py +++ b/tests/tpsLoad.py @@ -1,17 +1,21 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*-l -from sys import path -path.append("/usr/src/mytonctrl/") -from mytoncore import * +import time -Local = MyPyClass(__file__) -ton = MyTonCore() +from mypylib.mypylib import MyPyClass +from mytoncore import MyTonCore, Sleep + + +local = MyPyClass('./tests') +local.db["config"]["logLevel"] = "info" +load = 100 +ton = MyTonCore(local) def Init(): wallets = list() - Local.buffer["wallets"] = wallets + local.buffer["wallets"] = wallets walletsNameList = ton.GetWalletsNameList() # Create tests wallet @@ -50,7 +54,7 @@ def Init(): buff_wallet = wallet buff_wallet.oldseqno = ton.GetSeqno(wallet) ton.MoveGrams(wallet, testsWallet.addr, need, wait=False) - Local.AddLog(testsWallet.name + " <<< " + wallet.name) + local.AddLog(testsWallet.name + " <<< " + wallet.name) if buff_wallet: ton.WaitTransaction(buff_wallet, False) #end for @@ -63,12 +67,12 @@ def Init(): if wallet.account.status == "uninit": wallet.oldseqno = ton.GetSeqno(wallet) ton.SendFile(wallet.bocFilePath) - Local.AddLog(str(wallet.subwallet) + " - OK") + local.AddLog(str(wallet.subwallet) + " - OK") ton.WaitTransaction(wallets[-1]) #end define def Work(): - wallets = Local.buffer["wallets"] + wallets = local.buffer["wallets"] for i in range(load): if i + 1 == load: i = -1 @@ -78,7 +82,7 @@ def Work(): wallet2 = wallets[i+1] wallet1.oldseqno = ton.GetSeqno(wallet1) ton.MoveGrams(wallet1, wallet2.addr, 3.14, wait=False) - Local.AddLog(wallet1.name + " >>> " + wallet2.name) + local.AddLog(wallet1.name + " >>> " + wallet2.name) ton.WaitTransaction(wallets[-1]) #end define @@ -87,7 +91,7 @@ def General(): while True: time.sleep(1) Work() - Local.AddLog("Work - OK") + local.AddLog("Work - OK") #end while #end define @@ -96,13 +100,8 @@ def General(): ### ### Start test ### -Local = MyPyClass(__file__) -Local.db["config"]["logLevel"] = "info" -Local.Run() -ton = MyTonCore() -local.db["config"]["logLevel"] = "info" +local.Run() load = 100 - -Local.StartCycle(General, sec=1) +local.StartCycle(General, sec=1) Sleep() diff --git a/tests/tpsLoad2.py b/tests/tpsLoad2.py index 250c2800..b7f5f542 100644 --- a/tests/tpsLoad2.py +++ b/tests/tpsLoad2.py @@ -1,17 +1,20 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*-l -from sys import path -path.append("/usr/src/mytonctrl/") -from mytoncore import * +import time -Local = MyPyClass(__file__) -ton = MyTonCore() +from mypylib.mypylib import MyPyClass +from mytoncore import MyTonCore + +local = MyPyClass('./tests') +local.db["config"]["logLevel"] = "info" +load = 10 +ton = MyTonCore(local) def Init(): wallets = list() - Local.buffer["wallets"] = wallets + local.buffer["wallets"] = wallets walletsNameList = ton.GetWalletsNameList() # Create tests wallet @@ -50,7 +53,7 @@ def Init(): buff_wallet = wallet buff_wallet.oldseqno = ton.GetSeqno(wallet) ton.MoveGramsFromHW(wallet, [[testsWallet.addr, need]], wait=False) - Local.AddLog(testsWallet.name + " <<< " + str(wallet.subwallet)) + local.AddLog(testsWallet.name + " <<< " + str(wallet.subwallet)) if buff_wallet: ton.WaitTransaction(buff_wallet) #end for @@ -63,7 +66,7 @@ def Init(): if wallet.account.status == "uninit": wallet.oldseqno = ton.GetSeqno(wallet) ton.SendFile(wallet.bocFilePath) - Local.AddLog(str(wallet.subwallet) + " - OK") + local.AddLog(str(wallet.subwallet) + " - OK") ton.WaitTransaction(wallets[-1]) #end define @@ -75,7 +78,7 @@ def Work(): for wallet in wallets: wallet.oldseqno = ton.GetSeqno(wallet) ton.MoveGramsFromHW(wallet, destList, wait=False) - Local.AddLog(str(wallet.subwallet) + " " + wallet.addr + " >>> ") + local.AddLog(str(wallet.subwallet) + " " + wallet.addr + " >>> ") ton.WaitTransaction(wallets[-1]) #end define @@ -84,7 +87,7 @@ def General(): while True: time.sleep(1) Work() - Local.AddLog("Work - OK") + local.AddLog("Work - OK") #end while #end define @@ -93,15 +96,8 @@ def General(): ### ### Start test ### -Local = MyPyClass(__file__) -Local.db["config"]["logLevel"] = "info" -Local.Run() - -ton = MyTonCore() -local.db["config"]["logLevel"] = "info" -load = 10 - -Local.StartCycle(General, sec=1) +local.Run() +local.StartCycle(General, sec=1) while True: time.sleep(60) hour_str = time.strftime("%H")