From 55c94410d14824f099ddc00f02957f2165ac2712 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 29 May 2023 22:11:07 +0300 Subject: [PATCH 001/236] add controller --- mytoncore.py | 228 +++++++++++++++++++++++++++++++++++++++++++++++---- mytonctrl.py | 45 +++++++++- 2 files changed, 253 insertions(+), 20 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 01cf614e..42645b74 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -662,7 +662,7 @@ def GetDomainAdnlAddr(self, domainName): #end define def GetLocalWallet(self, walletName, version=None, subwallet=None): - local.AddLog("start GetLocalWallet function", "debug") + #local.AddLog("start GetLocalWallet function", "debug") if walletName is None: return None walletPath = self.walletsDir + walletName @@ -674,7 +674,7 @@ def GetLocalWallet(self, walletName, version=None, subwallet=None): #end define def GetWalletFromFile(self, filePath, version): - local.AddLog("start GetWalletFromFile function", "debug") + #local.AddLog("start GetWalletFromFile function", "debug") # Check input args if (".addr" in filePath): filePath = filePath.replace(".addr", '') @@ -725,7 +725,7 @@ def AddrFile2Object(self, object): #end define def WalletVersion2Wallet(self, wallet): - local.AddLog("start WalletVersion2Wallet function", "debug") + #local.AddLog("start WalletVersion2Wallet function", "debug") if wallet.version is not None: return walletsVersionList = self.GetWalletsVersionList() @@ -749,7 +749,7 @@ def SetWalletVersion(self, addrB64, version): #end define def GetWalletVersionFromHash(self, inputHash): - local.AddLog("start GetWalletVersionFromHash function", "debug") + #local.AddLog("start GetWalletVersionFromHash function", "debug") arr = dict() arr["v1r1"] = "d670136510daff4fee1889b8872c4c1e89872ffa1fe58a23a5f5d99cef8edf32" arr["v1r2"] = "2705a31a7ac162295c8aed0761cc6e031ab65521dd7b4a14631099e02de99e18" @@ -1339,10 +1339,10 @@ def PrepareComplaint(self, electionId, inputFileName): return fileName #end define - def CreateElectionRequest(self, wallet, startWorkTime, adnlAddr, maxFactor): + def CreateElectionRequest(self, addrB64, startWorkTime, adnlAddr, maxFactor): local.AddLog("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] + args = ["validator-elect-req.fif", addrB64, startWorkTime, maxFactor, adnlAddr, fileName] result = self.fift.Run(args) fileName = Pars(result, "Saved to file ", '\n') resultList = result.split('\n') @@ -1471,6 +1471,7 @@ def ProcessRecoverStake(self): def GetStake(self, account, args=None): stake = local.db.get("stake") usePool = local.db.get("usePool") + useController = local.db.get("useController") stakePercent = local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() validators = vconfig.get("validators") @@ -1497,6 +1498,8 @@ def GetStake(self, account, args=None): if stake is None and usePool: stake = account.balance - 20 + if stake is None and useController: + stake = account.balance - 20 if stake is None: sp = stakePercent / 100 if sp > 1 or sp < 0: @@ -1536,7 +1539,7 @@ def GetMaxFactor(self): #end define def GetValidatorWallet(self, mode="stake"): - local.AddLog("start GetValidatorWallet function", "debug") + #local.AddLog("start GetValidatorWallet function", "debug") walletName = local.db.get("validatorWalletName") wallet = self.GetLocalWallet(walletName) return wallet @@ -1544,17 +1547,13 @@ def GetValidatorWallet(self, mode="stake"): def ElectionEntry(self, args=None): usePool = local.db.get("usePool") + useController = local.db.get("useController") wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 if wallet is None: raise Exception("Validator wallet not found") #end if - if usePool: - pool = self.GetPool(mode="stake") - addrB64 = pool.addrB64 - #end if - local.AddLog("start ElectionEntry function", "debug") # Check if validator is not synchronized validatorStatus = self.GetValidatorStatus() @@ -1589,6 +1588,16 @@ def ElectionEntry(self, args=None): local.AddLog("Elections entry already completed", "info") return #end if + + if usePool: + pool = self.GetPool(mode="stake") + addrB64 = pool.addrB64 + elif useController: + controllerAddr = self.GetControllerAddress() + self.CheckController(controllerAddr) + self.CreateLoanRequest(controllerAddr) + addrB64 = self.GetControllerAddress() + #end if # Calculate stake account = self.GetAccount(addrB64) @@ -1610,15 +1619,23 @@ def ElectionEntry(self, args=None): # Create fift's. Continue with pool or walet if usePool: - var1 = self.CreateElectionRequest(pool, startWorkTime, adnlAddr, maxFactor) + var1 = self.CreateElectionRequest(pool.addrB64, startWorkTime, adnlAddr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) - validatorPubkey, resultFilePath = self.SignElectionRequestWithPoolWithValidator(pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) + validatorPubkey, resultFilePath = self.SignElectionRequestWithPool(pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) # Send boc file to TON resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 1.3) self.SendFile(resultFilePath, wallet) + elif useController: + var1 = self.CreateElectionRequest(controllerAddr, startWorkTime, adnlAddr, maxFactor) + validatorSignature = self.GetValidatorSignature(validatorKey, var1) + validatorPubkey, resultFilePath = self.SignElectionRequestWithController(controllerAddr, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) + + # Send boc file to TON + resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, controllerAddr, 1.03) + self.SendFile(resultFilePath, wallet) else: - var1 = self.CreateElectionRequest(wallet, startWorkTime, adnlAddr, maxFactor) + var1 = self.CreateElectionRequest(wallet.addrB64, startWorkTime, adnlAddr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) validatorPubkey, resultFilePath = self.SignElectionRequestWithValidator(wallet, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor) @@ -3495,8 +3512,8 @@ def GetPendingWithdraws(self): return pendingWithdraws #end define - def SignElectionRequestWithPoolWithValidator(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): - local.AddLog("start SignElectionRequestWithPoolWithValidator function", "debug") + def SignElectionRequestWithPool(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): + local.AddLog("start SignElectionRequestWithPool 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] @@ -3613,6 +3630,173 @@ def GetPoolData(self, addrB64): poolData["stakeHeldFor"] = data[15] return poolData #end define + + def CreateController(self, amount=1): + local.AddLog("start CreateController function", "debug") + wallet = self.GetValidatorWallet() + liquidPoolAddr = local.db.get("liquidPoolAddr") + contractPath = self.contractsDir + "jetton_pool/" + if not os.path.isdir(contractPath): + self.DownloadContract("https://github.com/ton-blockchain/jetton_pool") + #end if + + fileName = contractPath + "fift-scripts/deploy_controller.boc" + resultFilePath = self.SignBocWithWallet(wallet, fileName, liquidPoolAddr, amount) + self.SendFile(resultFilePath, wallet) + #end define + + def GetControllerAddress(self): + wallet = self.GetValidatorWallet() + addr_hash = HexAddr2Dec(wallet.addr) + liquidPoolAddr = local.db.get("liquidPoolAddr") + cmd = f"runmethodfull {liquidPoolAddr} get_controller_address_legacy {wallet.workchain} {addr_hash}" + result = self.liteClient.Run(cmd) + buff = self.Result2List(result) + wc = buff[0] + addr_hash = Dec2HexAddr(buff[1]) + addrFull = f"{wc}:{addr_hash}" + controllerAddr = self.AddrFull2AddrB64(addrFull) + return controllerAddr + #end define + + def CheckController(self, controllerAddr): + local.AddLog("start CheckController function", "debug") + controllerData = self.GetControllerData(controllerAddr) + saveControllerAddr = local.db.get("controllerAddr") + if controllerData["approved"] != -1: + raise Exception(f"GetControllerAddress error: controller not approved: {controllerAddr}") + if saveControllerAddr != controllerAddr: + local.AddLog("GetControllerAddress warning: controller is not up to date. Recreating the controller", "warning") + self.CreateController() + local.db["controllerAddr"] = controllerAddr + #end define + + def GetControllerData(self, controllerAddr): + cmd = f"runmethodfull {controllerAddr} get_validator_controller_data" + result = self.liteClient.Run(cmd) + data = self.Result2List(result) + if data is None: + return + result_vars = ["state", "approved", "stake_amount_sent", "stake_at", "saved_validator_set_hash", "validator_set_changes_count", "validator_set_change_time", "stake_held_for", "borrowed_amount", "borrowing_time"] + controllerData = dict() + for name in result_vars: + controllerData[name] = data.pop(0) + return controllerData + #end define + + def CreateLoanRequest(self, controllerAddr): + local.AddLog("start CreateLoanRequest function", "debug") + min_loan = local.db.get("min_loan", 41000) + max_loan = local.db.get("max_loan", 43000) + max_interest_percent = local.db.get("max_interest_percent", 0.015) + # TODO + # Проверить наличие старого кредита + controllerData = self.GetControllerData(controllerAddr) + if controllerData["borrowed_amount"] != 0: + local.AddLog("CreateLoanRequest info: loan already taken") + return + #end if + + wallet = self.GetValidatorWallet() + max_interest = int(max_interest_percent*65536) + fiftScript = self.contractsDir + "jetton_pool/fift-scripts/generate-loan-request.fif" + resultFilePath = self.tempDir + self.nodeName + wallet.name + "_loan_request.boc" + args = [fiftScript, min_loan, max_loan, max_interest, resultFilePath] + result = self.fift.Run(args) + resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, controllerAddr, 1.01) + self.SendFile(resultFilePath, wallet) + self.WaitLoan(controllerAddr) + #end define + + def WaitLoan(self, controllerAddr): + local.AddLog("start WaitLoan function", "debug") + for i in range(10): + time.sleep(3) + controllerData = self.GetControllerData(controllerAddr) + if controllerData["borrowed_amount"] != 0: + return + raise Exception("WaitLoan error: time out") + #end define + + def ReturnUnusedLoan(self, controllerAddr): + local.AddLog("start ReturnUnusedLoan function", "debug") + wallet = self.GetValidatorWallet() + fileName = self.contractsDir + "jetton_pool/fift-scripts/return_unused_loan.boc" + resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.05) + self.SendFile(resultFilePath, wallet) + #end define + + def WithdrawFromController(self, controllerAddr, amount): + local.AddLog("start WithdrawFromController function", "debug") + wallet = self.GetValidatorWallet() + fiftScript = self.contractsDir + "jetton_pool/fift-scripts/withdraw-controller.fif" + resultFilePath = self.tempDir + self.nodeName + wallet.name + "_withdraw_request.boc" + args = [fiftScript, amount, resultFilePath] + result = self.fift.Run(args) + resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, controllerAddr, 1.06) + self.SendFile(resultFilePath, wallet) + #end define + + def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): + local.AddLog("start SignElectionRequestWithController function", "debug") + fileName = self.tempDir + str(startWorkTime) + "_validator-query.boc" + fiftScript = self.contractsDir + "jetton_pool/fift-scripts/controller-elect-signed.fif" + args = [fiftScript, controllerAddr, startWorkTime, maxFactor, adnlAddr, validatorPubkey_b64, validatorSignature, fileName, stake] + print(f"args: {args}") + result = self.fift.Run(args) + print(f"result: {result}") + pubkey = Pars(result, "validator public key ", '\n') + fileName = Pars(result, "Saved to file ", '\n') + return pubkey, fileName + #end define + + def ControllerUpdateValidatorSet(self): + local.AddLog("start ControllerUpdateValidatorSet function", "debug") + wallet = self.GetValidatorWallet() + controllerAddr = self.GetControllerAddress() + controllerData = self.GetControllerData(controllerAddr) + if controllerData is None: + return + #en if + + timeNow = int(time.time()) + config34 = self.GetConfig34() + fullElectorAddr = self.GetFullElectorAddr() + returnedStake = self.GetReturnedStake(fullElectorAddr, controllerAddr) + print(f"Controller returnedStake: {returnedStake}") + pendingWithdraws = self.GetPendingWithdraws() + if (controllerData["state"] == 3 and + controllerData["validator_set_changes_count"] < 2 and + controllerData["validator_set_change_time"] < config34["startWorkTime"]): + self.ControllerProcessUpdateValidatorSet(controllerAddr, wallet) + controllerData = self.GetControllerData(controllerAddr) + if (returnedStake > 0 and + controllerData["state"] == 3 and + controllerData["validator_set_changes_count"] >= 2 and + timeNow - controllerData["validator_set_change_time"] > controllerData["stake_held_for"] + 60): + self.ControllerRecoverStake(controllerAddr) + #end define + + def ControllerProcessUpdateValidatorSet(self, controllerAddr, wallet): + local.AddLog("start ControllerProcessUpdateValidatorSet function", "debug") + fileName = self.contractsDir + "jetton_pool/fift-scripts/update_validator_hash.boc" + resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.07) + self.SendFile(resultFilePath, wallet) + local.AddLog("ControllerProcessUpdateValidatorSet completed") + #end define + + def ControllerRecoverStake(self, controllerAddr): + wallet = self.GetValidatorWallet() + if wallet is None: + raise Exception("Validator wallet not found") + #end if + + local.AddLog("start ControllerRecoverStake function", "debug") + fileName = self.contractsDir + "jetton_pool/fift-scripts/recover_stake.boc" + resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.04) + self.SendFile(resultFilePath, wallet) + local.AddLog("ControllerRecoverStake completed") + #end define def GetNetworkName(self): mainnetValidatorsElectedFor = 65536 @@ -3950,10 +4134,15 @@ def ValidatorDownEvent(): def Elections(ton): usePool = local.db.get("usePool") + useController = local.db.get("useController") if usePool == True: ton.PoolsUpdateValidatorSet() ton.RecoverStake() ton.ElectionEntry() + elif useController == True: + ton.ControllerUpdateValidatorSet() + ton.RecoverStake() + ton.ElectionEntry() else: ton.RecoverStake() ton.ElectionEntry() @@ -4410,6 +4599,11 @@ def Dec2HexAddr(dec): return h64 #end define +def HexAddr2Dec(h): + d = int(h, 16) + return d +#end define + def xhex2hex(x): try: b = x[1:] diff --git a/mytonctrl.py b/mytonctrl.py index 665755a7..7ccc7f3a 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -69,6 +69,12 @@ def Init(argv): 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.AddItem("new_controller", NewController, local.Translate("_")) + console.AddItem("get_controller_data", GetControllerData, local.Translate("_")) + console.AddItem("create_loan_request", CreateLoanRequest, local.Translate("_")) + console.AddItem("return_unused_loan", ReturnUnusedLoan, local.Translate("_")) + console.AddItem("withdraw_from_controller", WithdrawFromController, local.Translate("_")) # Process input parameters opts, args = getopt.getopt(argv,"hc:w:",["config=","wallets="]) @@ -1151,9 +1157,42 @@ def UpdateValidatorSet(args): except: ColorPrint("{red}Bad args. Usage:{endc} update_validator_set ") return - wallet = self.GetValidatorWallet() - self.PoolUpdateValidatorSet(poolAddr, wallet) - ColorPrint("DeletePool - {green}OK{endc}") + wallet = ton.GetValidatorWallet() + ton.PoolUpdateValidatorSet(poolAddr, wallet) + ColorPrint("UpdateValidatorSet - {green}OK{endc}") +#end define + +def NewController(args): + if len(args) == 1: + amount = int(args[0]) + else: + amount = 1 + ton.CreateController(amount) + ColorPrint("NewController - {green}OK{endc}") +#end define + +def GetControllerData(args): + controllerAddr = ton.GetControllerAddress() + data = ton.GetControllerData(controllerAddr) + print(f"GetControllerAddress: {controllerAddr}") + print(f"GetControllerData: {data}") +#end define + +def CreateLoanRequest(args): + controllerAddr = ton.GetControllerAddress() + ton.CreateLoanRequest(controllerAddr) +#end define + +def ReturnUnusedLoan(args): + controllerAddr = ton.GetControllerAddress() + ton.ReturnUnusedLoan(controllerAddr) +#end define + +def WithdrawFromController(args): + controllerAddr = ton.GetControllerAddress() + account = ton.GetAccount(controllerAddr) + amount = account.balance-10.1 + ton.WithdrawFromController(controllerAddr, amount) #end define From 3b01f119acd4b32ced95d9160cf914a5f6476f29 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 14 Jun 2023 16:53:53 +0300 Subject: [PATCH 002/236] Update mytoncore.py --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 42645b74..0304c342 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3637,7 +3637,7 @@ def CreateController(self, amount=1): liquidPoolAddr = local.db.get("liquidPoolAddr") contractPath = self.contractsDir + "jetton_pool/" if not os.path.isdir(contractPath): - self.DownloadContract("https://github.com/ton-blockchain/jetton_pool") + self.DownloadContract("https://github.com/igroman787/jetton_pool") #end if fileName = contractPath + "fift-scripts/deploy_controller.boc" From 998f509fef8ecdcb94c7f5e0376abb72f4988dcf Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 20 Jun 2023 23:19:29 +0300 Subject: [PATCH 003/236] add controller checks --- docs/ru/controllers.md | 83 ++++++++++++++++++++++ mytoncore.py | 153 ++++++++++++++++++++++++++++++----------- mytonctrl.py | 61 ++++++++++------ 3 files changed, 236 insertions(+), 61 deletions(-) create mode 100644 docs/ru/controllers.md diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md new file mode 100644 index 00000000..87a7d21e --- /dev/null +++ b/docs/ru/controllers.md @@ -0,0 +1,83 @@ +# Контроллеры + +## Запуск валидатора в режиме работы контроллеров + +1. Подготовьте аппаратное обеспечение для валидатора - 32 виртуальных ядер, 64GB памяти, 1TB SSD, фиксированный IP-адрес, скорость интернета 1Gb/s. + + Для поддержания стабильности сети рекомендуется разместить валидаторы в различных местах по всему миру, а не концентрировать их в одном дата-центре. Вы можете использовать [этот сайт](https://status.toncenter.com/) для определения нагрузки на различные места. Согласно карте, высокая нагрузка на дата-центры в Европе, особенно в Финляндии, Германии и Париже. Поэтому использование провайдеров, таких как Hetzner и OVH, не рекомендуется. + + > Ваше оборудование должно соответствовать указанной конфигурации или быть выше. Запуск валидатора на слабом оборудовании негативно влияет на сеть и может привести к штрафам. + + > С мая 2021 года Hetzner запретил майнинг на своих серверах, в настоящее время под это правило попадают алгоритмы PoW и PoS. Установка даже обычного узла будет считаться нарушением условий договора. + + > **Рекомендуемые провайдеры:** [Amazon](https://aws.amazon.com/), [DigitalOcean](https://www.digitalocean.com/), [Linode](https://www.linode.com/), [Alibaba Cloud](https://alibabacloud.com/), [Latitude](https://www.latitude.sh/). + +2. Установите и синхронизируйте **mytonctrl** в соответствии с описанием в [этой инструкции](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/ru/manual-ubuntu.md) — следуйте **только** пунктам 1, 2 и 3. + + Вы также можете обратиться к этой [Видеоинструкции](https://ton.org/docs/#/nodes/run-node) для дополнительной помощи. + +3. Переведите 1 TON на адрес кошелька валидатора, который отображается в списке `wl`. + +4. Используйте команду `aw` для активации кошелька валидатора. + +5. Переведите достаточно TON на адрес кошелька валидатора. + +6. Задайте адрес ликвидного пула, котрый будет одалживать TON для валидации: + ``` + set liquid_pool_addr EQCaHqeMgvlZRS6mDA0lzp78CF3QRNWfBQ86rE1SDcK4dijQ + ``` + +7. Задайте параметры кредитования, котрые вам подходят: + ``` + set min_loan 41000 + set max_loan 43000 + set max_interest_percent 1.5 + ``` + + где `min_loan` - это минимальная сумма кредита который мы готовы получить у ликвидного пула, + `max_loan` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, + `max_interest_percent` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. + +8. Создайте два контроллера одной командой: + + ``` + new_controllers + ``` + + > (!) Используйте https://tonmon.xyz/, чтобы определить текущую минимальную ставку валидатора. + +9. Введите `controllers_list` чтобы отобразить адреса контроллеров: + + ``` + controllers_list + Address Status Balance + kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS active 0.704345 + kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 + ``` + +10. Совершите депозит валидатора в каждый кнтроллер: + + ``` + deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 + deposit_to_controller kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN 10000 + ``` + + где `10000` TON - это сумма депозита. + +11. Активируйте режим работы контроллеров: + + ```bash + set useController true + set stake null + ``` + + > (!) Если до этого вы использовали номинатор-пулы, не забудьте отключить их использование командой `set usePool false`. + + +## Переключение обычного валидатора в режим работы контроллеров + +1. Введите `set stake 0`, чтобы отключить участие в выборах. + +2. Дождитесь, когда оба ваших депозита вернутся от электора. + +3. Следуйте инструкциям "Запуск валидатора в режиме работы контроллеров", начиная с **6-го шага**. \ No newline at end of file diff --git a/mytoncore.py b/mytoncore.py index 0304c342..c20f47f6 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -1399,7 +1399,9 @@ def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): #end if seqno = self.GetSeqno(wallet) - resultFilePath = self.tempDir + self.nodeName + wallet.name + "_wallet-query" + #resultFilePath = self.tempDir + self.nodeName + wallet.name + "_wallet-query" + boc_name = os.path.splitext(os.path.basename(bocPath))[0] + resultFilePath = self.tempDir + self.nodeName + boc_name + "_sign_with_" + wallet.name if "v1" in wallet.version: fiftScript = "wallet.fif" args = [fiftScript, wallet.path, dest, seqno, coins, "-B", bocPath, resultFilePath] @@ -1499,7 +1501,7 @@ def GetStake(self, account, args=None): if stake is None and usePool: stake = account.balance - 20 if stake is None and useController: - stake = account.balance - 20 + stake = account.balance - 30 if stake is None: sp = stakePercent / 100 if sp > 1 or sp < 0: @@ -1542,6 +1544,8 @@ def GetValidatorWallet(self, mode="stake"): #local.AddLog("start GetValidatorWallet function", "debug") walletName = local.db.get("validatorWalletName") wallet = self.GetLocalWallet(walletName) + if wallet is None: + raise Exception("GetValidatorWallet error: Validator wallet not found") return wallet #end define @@ -1550,9 +1554,6 @@ def ElectionEntry(self, args=None): useController = local.db.get("useController") wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 - if wallet is None: - raise Exception("Validator wallet not found") - #end if local.AddLog("start ElectionEntry function", "debug") # Check if validator is not synchronized @@ -1593,10 +1594,10 @@ def ElectionEntry(self, args=None): pool = self.GetPool(mode="stake") addrB64 = pool.addrB64 elif useController: - controllerAddr = self.GetControllerAddress() + controllerAddr = self.GetController(mode="stake") self.CheckController(controllerAddr) self.CreateLoanRequest(controllerAddr) - addrB64 = self.GetControllerAddress() + addrB64 = controllerAddr #end if # Calculate stake @@ -1672,10 +1673,6 @@ def GetValidatorKeyByTime(self, startWorkTime, endWorkTime): def RecoverStake(self): wallet = self.GetValidatorWallet() - if wallet is None: - raise Exception("Validator wallet not found") - #end if - local.AddLog("start RecoverStake function", "debug") fullElectorAddr = self.GetFullElectorAddr() returnedStake = self.GetReturnedStake(fullElectorAddr, wallet.addrB64) @@ -1692,10 +1689,6 @@ def RecoverStake(self): def PoolRecoverStake(self, poolAddr): wallet = self.GetValidatorWallet() - if wallet is None: - raise Exception("Validator wallet not found") - #end if - local.AddLog("start PoolRecoverStake function", "debug") resultFilePath = self.PoolProcessRecoverStake() resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, poolAddr, 1.2) @@ -3630,26 +3623,38 @@ def GetPoolData(self, addrB64): poolData["stakeHeldFor"] = data[15] return poolData #end define + + def GetLiquidPoolAddr(self): + liquid_pool_addr = local.db.get("liquid_pool_addr") + if liquid_pool_addr is None: + raise Exception("GetLiquidPoolAddr error: liquid_pool_addr not set") + return liquid_pool_addr + #end define - def CreateController(self, amount=1): - local.AddLog("start CreateController function", "debug") + def CreateControllers(self): + local.AddLog("start CreateControllers function", "debug") wallet = self.GetValidatorWallet() - liquidPoolAddr = local.db.get("liquidPoolAddr") + liquid_pool_addr = self.GetLiquidPoolAddr() contractPath = self.contractsDir + "jetton_pool/" if not os.path.isdir(contractPath): self.DownloadContract("https://github.com/igroman787/jetton_pool") #end if - fileName = contractPath + "fift-scripts/deploy_controller.boc" - resultFilePath = self.SignBocWithWallet(wallet, fileName, liquidPoolAddr, amount) - self.SendFile(resultFilePath, wallet) + fileName0 = contractPath + "fift-scripts/deploy_controller0.boc" + fileName1 = contractPath + "fift-scripts/deploy_controller1.boc" + resultFilePath0 = self.SignBocWithWallet(wallet, fileName0, liquid_pool_addr, 1) + self.SendFile(resultFilePath0, wallet) + time.sleep(10) + resultFilePath1 = self.SignBocWithWallet(wallet, fileName1, liquid_pool_addr, 1) + self.SendFile(resultFilePath1, wallet) + local.db["controllersAddr"] = self.GetControllers() #end define - def GetControllerAddress(self): + def GetControllerAddress(self, controller_id): wallet = self.GetValidatorWallet() addr_hash = HexAddr2Dec(wallet.addr) - liquidPoolAddr = local.db.get("liquidPoolAddr") - cmd = f"runmethodfull {liquidPoolAddr} get_controller_address_legacy {wallet.workchain} {addr_hash}" + liquid_pool_addr = self.GetLiquidPoolAddr() + cmd = f"runmethodfull {liquid_pool_addr} get_controller_address_legacy {controller_id} {wallet.workchain} {addr_hash}" result = self.liteClient.Run(cmd) buff = self.Result2List(result) wc = buff[0] @@ -3661,14 +3666,68 @@ def GetControllerAddress(self): def CheckController(self, controllerAddr): local.AddLog("start CheckController function", "debug") + now = GetTimestamp() controllerData = self.GetControllerData(controllerAddr) - saveControllerAddr = local.db.get("controllerAddr") + saveControllersAddr = local.db.get("controllersAddr", list()) if controllerData["approved"] != -1: - raise Exception(f"GetControllerAddress error: controller not approved: {controllerAddr}") - if saveControllerAddr != controllerAddr: - local.AddLog("GetControllerAddress warning: controller is not up to date. Recreating the controller", "warning") - self.CreateController() - local.db["controllerAddr"] = controllerAddr + raise Exception(f"CheckController error: controller not approved: {controllerAddr}") + if controllerData["borrowed_amount"] > 0 and controllerData["borrowing_time"] > now: + local.AddLog("CheckController warning: controller has loan. Return unused loan", "warning") + self.ReturnUnusedLoan(controllerAddr) + if controllerAddr not in saveControllersAddr: + raise Exception("CheckController error: controller is not up to date. Use new_controllers") + #end define + + def GetControllers(self): + local.AddLog("start GetControllers function", "debug") + controller0 = self.GetControllerAddress(controller_id=0) + controller1 = self.GetControllerAddress(controller_id=1) + controllers = [controller0, controller1] + return controllers + #end define + + def GetController(self, mode): + controllers = self.GetControllers() + for controllerAddr in controllers: + if mode == "stake" and self.IsControllerReadyToStake(controllerAddr): + return controllerAddr + if mode == "vote" and self.IsControllerReadyToVote(controllerAddr): + return controllerAddr + raise Exception("Validator controller not found or not ready") + #end define + + def GetControllerRequiredBalanceForLoan(self, controllerAddr, credit, interest): + cmd = f"runmethodfull {controllerAddr} required_balance_for_loan {credit} {interest}" + result = self.liteClient.Run(cmd) + data = self.Result2List(result) + if data is None: + return + result_vars = ["min_amount", "validator_amount"] + result = dict() + for name in result_vars: + result[name] = data.pop(0) + return result + #end define + + def GetControllerLastSentStakeTime(self, addrB64): + controllerData = self.GetControllerData(addrB64) + return controllerData["stake_at"] + #end define + + def IsControllerReadyToStake(self, addrB64): + now = GetTimestamp() + config15 = self.GetConfig15() + lastSentStakeTime = self.GetControllerLastSentStakeTime(addrB64) + stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] + result = lastSentStakeTime + stakeFreezeDelay < now + print(f"{addrB64}: {result}. {lastSentStakeTime}, {stakeFreezeDelay}, {now}") + return result + #end define + + def IsControllerReadyToVote(self, addrB64): + vwl = self.GetValidatorsWalletsList() + result = addrB64 in vwl + return result #end define def GetControllerData(self, controllerAddr): @@ -3677,7 +3736,7 @@ def GetControllerData(self, controllerAddr): data = self.Result2List(result) if data is None: return - result_vars = ["state", "approved", "stake_amount_sent", "stake_at", "saved_validator_set_hash", "validator_set_changes_count", "validator_set_change_time", "stake_held_for", "borrowed_amount", "borrowing_time"] + result_vars = ["state", "halted", "approved", "stake_amount_sent", "stake_at", "saved_validator_set_hash", "validator_set_changes_count", "validator_set_change_time", "stake_held_for", "borrowed_amount", "borrowing_time"] controllerData = dict() for name in result_vars: controllerData[name] = data.pop(0) @@ -3688,7 +3747,8 @@ def CreateLoanRequest(self, controllerAddr): local.AddLog("start CreateLoanRequest function", "debug") min_loan = local.db.get("min_loan", 41000) max_loan = local.db.get("max_loan", 43000) - max_interest_percent = local.db.get("max_interest_percent", 0.015) + max_interest_percent = local.db.get("max_interest_percent", 1.5) + max_interest = int(max_interest_percent/100*65536) # TODO # Проверить наличие старого кредита controllerData = self.GetControllerData(controllerAddr) @@ -3697,8 +3757,13 @@ def CreateLoanRequest(self, controllerAddr): return #end if + # Проверить хватает ли ставки валидатора + min_amount, validator_amount = self.GetControllerRequiredBalanceForLoan(controllerAddr, max_loan, max_interest) + if validator_amount < min_amount: + raise Exception("CreateLoanRequest error: too_high_loan_request_amount") + #end if + wallet = self.GetValidatorWallet() - max_interest = int(max_interest_percent*65536) fiftScript = self.contractsDir + "jetton_pool/fift-scripts/generate-loan-request.fif" resultFilePath = self.tempDir + self.nodeName + wallet.name + "_loan_request.boc" args = [fiftScript, min_loan, max_loan, max_interest, resultFilePath] @@ -3725,6 +3790,14 @@ def ReturnUnusedLoan(self, controllerAddr): resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.05) self.SendFile(resultFilePath, wallet) #end define + + def DepositToController(self, controllerAddr, amount): + local.AddLog("start DepositToController function", "debug") + wallet = self.GetValidatorWallet() + fileName = self.contractsDir + "jetton_pool/fift-scripts/top-up.boc" + resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, amount) + self.SendFile(resultFilePath, wallet) + #end define def WithdrawFromController(self, controllerAddr, amount): local.AddLog("start WithdrawFromController function", "debug") @@ -3749,11 +3822,17 @@ def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlA fileName = Pars(result, "Saved to file ", '\n') return pubkey, fileName #end define - + def ControllerUpdateValidatorSet(self): local.AddLog("start ControllerUpdateValidatorSet function", "debug") + controllers = self.GetControllers() + for controller in controllers: + self.ControllerUpdateValidatorSetProcess(controller) + #end define + + def ControllerUpdateValidatorSetProcess(self, controllerAddr): + local.AddLog("start ControllerUpdateValidatorSetProcess function", "debug") wallet = self.GetValidatorWallet() - controllerAddr = self.GetControllerAddress() controllerData = self.GetControllerData(controllerAddr) if controllerData is None: return @@ -3787,10 +3866,6 @@ def ControllerProcessUpdateValidatorSet(self, controllerAddr, wallet): def ControllerRecoverStake(self, controllerAddr): wallet = self.GetValidatorWallet() - if wallet is None: - raise Exception("Validator wallet not found") - #end if - local.AddLog("start ControllerRecoverStake function", "debug") fileName = self.contractsDir + "jetton_pool/fift-scripts/recover_stake.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.04) diff --git a/mytonctrl.py b/mytonctrl.py index 7ccc7f3a..8ae23805 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -70,10 +70,10 @@ def Init(argv): console.AddItem("withdraw_from_pool", WithdrawFromPool, local.Translate("withdraw_from_pool_cmd")) console.AddItem("delete_pool", DeletePool, local.Translate("delete_pool_cmd")) - console.AddItem("new_controller", NewController, local.Translate("_")) + console.AddItem("new_controllers", NewControllers, local.Translate("_")) + console.AddItem("controllers_list", PrintControllersList, local.Translate("_")) console.AddItem("get_controller_data", GetControllerData, local.Translate("_")) - console.AddItem("create_loan_request", CreateLoanRequest, local.Translate("_")) - console.AddItem("return_unused_loan", ReturnUnusedLoan, local.Translate("_")) + console.AddItem("deposit_to_controller", DepositToController, local.Translate("_")) console.AddItem("withdraw_from_controller", WithdrawFromController, local.Translate("_")) # Process input parameters @@ -1162,34 +1162,51 @@ def UpdateValidatorSet(args): ColorPrint("UpdateValidatorSet - {green}OK{endc}") #end define -def NewController(args): - if len(args) == 1: - amount = int(args[0]) - else: - amount = 1 - ton.CreateController(amount) - ColorPrint("NewController - {green}OK{endc}") +def NewControllers(args): + ton.CreateControllers() + ColorPrint("NewControllers - {green}OK{endc}") #end define -def GetControllerData(args): - controllerAddr = ton.GetControllerAddress() - data = ton.GetControllerData(controllerAddr) - print(f"GetControllerAddress: {controllerAddr}") - print(f"GetControllerData: {data}") +def PrintControllersList(args): + table = list() + table += [["Address", "Status", "Balance"]] + controllers = ton.GetControllers() + if (controllers is None or len(controllers) == 0): + print("No data") + return + for controllerAddr in controllers: + account = ton.GetAccount(controllerAddr) + table += [[controllerAddr, account.status, account.balance]] + PrintTable(table) #end define -def CreateLoanRequest(args): - controllerAddr = ton.GetControllerAddress() - ton.CreateLoanRequest(controllerAddr) +def GetControllerData(args): + try: + controllerAddr = args[0] + except: + ColorPrint("{red}Bad args. Usage:{endc} get_controller_data ") + return + data = ton.GetControllerData(controllerAddr) + print(f"ControllerData: {data}") #end define -def ReturnUnusedLoan(args): - controllerAddr = ton.GetControllerAddress() - ton.ReturnUnusedLoan(controllerAddr) +def DepositToController(args): + try: + controllerAddr = args[0] + amount = float(args[1]) + except: + ColorPrint("{red}Bad args. Usage:{endc} deposit_to_controller ") + return + ton.DepositToController(controllerAddr, amount) #end define def WithdrawFromController(args): - controllerAddr = ton.GetControllerAddress() + try: + controllerAddr = args[0] + except: + ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_controller ") + return + ton.CheckController(controllerAddr) account = ton.GetAccount(controllerAddr) amount = account.balance-10.1 ton.WithdrawFromController(controllerAddr, amount) From fd1bfd2f9bc6158572f6a6b55ecf81b55de8779f Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:12:11 +0300 Subject: [PATCH 004/236] Update controllers.md --- docs/ru/controllers.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md index 87a7d21e..ec77ffb1 100644 --- a/docs/ru/controllers.md +++ b/docs/ru/controllers.md @@ -10,8 +10,6 @@ > С мая 2021 года Hetzner запретил майнинг на своих серверах, в настоящее время под это правило попадают алгоритмы PoW и PoS. Установка даже обычного узла будет считаться нарушением условий договора. - > **Рекомендуемые провайдеры:** [Amazon](https://aws.amazon.com/), [DigitalOcean](https://www.digitalocean.com/), [Linode](https://www.linode.com/), [Alibaba Cloud](https://alibabacloud.com/), [Latitude](https://www.latitude.sh/). - 2. Установите и синхронизируйте **mytonctrl** в соответствии с описанием в [этой инструкции](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/ru/manual-ubuntu.md) — следуйте **только** пунктам 1, 2 и 3. Вы также можете обратиться к этой [Видеоинструкции](https://ton.org/docs/#/nodes/run-node) для дополнительной помощи. @@ -44,8 +42,6 @@ new_controllers ``` - > (!) Используйте https://tonmon.xyz/, чтобы определить текущую минимальную ставку валидатора. - 9. Введите `controllers_list` чтобы отобразить адреса контроллеров: ``` @@ -55,7 +51,7 @@ kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 ``` -10. Совершите депозит валидатора в каждый кнтроллер: +10. Совершите депозит валидатора в каждый контроллер: ``` deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 From f2b4203105a3faa29d1303ea73bdba7a0fafc19f Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 21 Jun 2023 11:37:44 +0300 Subject: [PATCH 005/236] Update controllers.md --- docs/ru/controllers.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md index ec77ffb1..c0320146 100644 --- a/docs/ru/controllers.md +++ b/docs/ru/controllers.md @@ -22,7 +22,7 @@ 6. Задайте адрес ликвидного пула, котрый будет одалживать TON для валидации: ``` - set liquid_pool_addr EQCaHqeMgvlZRS6mDA0lzp78CF3QRNWfBQ86rE1SDcK4dijQ + set liquid_pool_addr ``` 7. Задайте параметры кредитования, котрые вам подходят: @@ -32,9 +32,9 @@ set max_interest_percent 1.5 ``` - где `min_loan` - это минимальная сумма кредита который мы готовы получить у ликвидного пула, - `max_loan` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, - `max_interest_percent` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. + где `41000` - это минимальная сумма кредита который мы готовы получить у ликвидного пула, + `43000` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, + `1.5` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. 8. Создайте два контроллера одной командой: @@ -60,7 +60,9 @@ где `10000` TON - это сумма депозита. -11. Активируйте режим работы контроллеров: +11. Получите аппрувал контроллеров. У каждого пула может быть своя политика выдачи аппруволов, уточняйте у оператора. + +12. Активируйте режим работы контроллеров: ```bash set useController true From e2f09722b317ffb75d35ce066f398b1aecb3ff6a Mon Sep 17 00:00:00 2001 From: AlexG Date: Wed, 21 Jun 2023 13:27:25 +0400 Subject: [PATCH 006/236] controllers_translate_added - Added controlleres.md en version. - Minor fixes for links in the controllers.md in the ru version. --- docs/en/controllers.md | 83 ++++++++++++++++++++++++++++++++++++++++++ docs/ru/controllers.md | 13 ++++--- 2 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 docs/en/controllers.md diff --git a/docs/en/controllers.md b/docs/en/controllers.md new file mode 100644 index 00000000..52150228 --- /dev/null +++ b/docs/en/controllers.md @@ -0,0 +1,83 @@ +# Controllers + +## Launching a Validator in Controller Mode + +1. Prepare the hardware for the validator - 32 virtual cores, 64GB of memory, 1TB SSD, fixed IP address, and 1Gb/s internet speed. + + To maintain network stability, it is recommended to place validators in different locations around the world, rather than concentrating them in a single data center. You can use [this site](https://status.toncenter.com/) to determine the load on various locations. According to the map, there is a high load on data centers in Europe, especially in Finland, Germany, and Paris. Therefore, using providers such as Hetzner and OVH is not recommended. + + > Ensure your hardware meets or exceeds the specified configuration. Running the validator on inappropriate hardware can harm the network and result in penalties. + > Since May 2021, Hetzner has prohibited mining on its servers. This rule currently applies to both PoW and PoS algorithms. Even installing a regular node will be considered a breach of contract. + +2. Install and synchronize **mytonctrl** according to the description in [this instruction](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/en/manual-ubuntu.md) — follow **only** paragraphs 1, 2, and 3. + + You can also refer to this [Video Tutorial](https://docs.ton.org/participate/run-nodes/full-node#installation) for additional help. + +3. Transfer 1 TON to the validator wallet address, which is displayed in the `wl` list. + +4. Use the `aw` command to activate the validator's wallet. + +5. Transfer enough TON to the validator wallet address. + +6. Set the liquid pool address, which will lend TON for validation: + ``` + set liquid_pool_addr + ``` + +7. Set the lending parameters that acceptable to you: + ``` + set min_loan 41000 + set max_loan 43000 + set max_interest_percent 1.5 + ``` + + where +* `41000` is the minimum loan amount we are willing to receive from the liquid pool, +* `43000` is the maximum loan amount we are willing to receive from the liquid pool, +* `1.5` 1.5 is the maximum interest rate value for the liquid pool per validation cycle, which we have agreed upon. + +8. Create two controllers with a single command: + + ``` + new_controllers + ``` + +9. Enter `controllers_list` to display the controller addresses: + + ``` + controllers_list + Address Status Balance + kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS active 0.704345 + kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 + ``` + +10. Make a validator deposit in each controller: + + +``` +deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 +deposit_to_controller kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN 10000 +``` + + +where `10000` TON is the deposit amount. + +11. Get approval for the controllers. Each pool may have its own approval issuance policy, check with the operator. + +12. Set controller mode: + + ```bash + set useController true + set stake null + ``` + +> (!) If you were previously using nominator pools, do not forget to disable them using the `set usePool false` command. + + +## Switching a Regular Validator to Controller Operating Mode + +1. Enter `set stake 0` to stop participating in elections. + +2. Wait until both of your deposits have been returned from the Elector. + +3. Follow the instructions under "Launching a Validator in Controller Mode", beginning with **Step 6**. \ No newline at end of file diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md index c0320146..aff65fd5 100644 --- a/docs/ru/controllers.md +++ b/docs/ru/controllers.md @@ -12,7 +12,7 @@ 2. Установите и синхронизируйте **mytonctrl** в соответствии с описанием в [этой инструкции](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/ru/manual-ubuntu.md) — следуйте **только** пунктам 1, 2 и 3. - Вы также можете обратиться к этой [Видеоинструкции](https://ton.org/docs/#/nodes/run-node) для дополнительной помощи. + Вы также можете обратиться к этой [Видеоинструкции](https://docs.ton.org/participate/run-nodes/full-node#installation) для дополнительной помощи. 3. Переведите 1 TON на адрес кошелька валидатора, который отображается в списке `wl`. @@ -20,21 +20,22 @@ 5. Переведите достаточно TON на адрес кошелька валидатора. -6. Задайте адрес ликвидного пула, котрый будет одалживать TON для валидации: +6. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: ``` set liquid_pool_addr ``` -7. Задайте параметры кредитования, котрые вам подходят: +7. Задайте параметры кредитования, которые вам подходят: ``` set min_loan 41000 set max_loan 43000 set max_interest_percent 1.5 ``` - где `41000` - это минимальная сумма кредита который мы готовы получить у ликвидного пула, - `43000` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, - `1.5` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. + где +* `41000` - это минимальная сумма кредита который мы готовы получить у ликвидного пула, +* `43000` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, +* `1.5` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. 8. Создайте два контроллера одной командой: From c292552d7c77cf49a6d542e094f31455a9802717 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 1 Jul 2023 14:01:36 +0300 Subject: [PATCH 007/236] add `calculate_annual_controller_percentage` --- mytoncore.py | 21 ++++++++++++++++++--- mytonctrl.py | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index c20f47f6..f05efd96 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3666,12 +3666,12 @@ def GetControllerAddress(self, controller_id): def CheckController(self, controllerAddr): local.AddLog("start CheckController function", "debug") - now = GetTimestamp() + config34 = self.GetConfig34() controllerData = self.GetControllerData(controllerAddr) saveControllersAddr = local.db.get("controllersAddr", list()) if controllerData["approved"] != -1: raise Exception(f"CheckController error: controller not approved: {controllerAddr}") - if controllerData["borrowed_amount"] > 0 and controllerData["borrowing_time"] > now: + if controllerData["borrowed_amount"] > 0 and config34["startWorkTime"] > controllerData["borrowing_time"]: local.AddLog("CheckController warning: controller has loan. Return unused loan", "warning") self.ReturnUnusedLoan(controllerAddr) if controllerAddr not in saveControllersAddr: @@ -3749,7 +3749,7 @@ def CreateLoanRequest(self, controllerAddr): max_loan = local.db.get("max_loan", 43000) max_interest_percent = local.db.get("max_interest_percent", 1.5) max_interest = int(max_interest_percent/100*65536) - # TODO + # Проверить наличие старого кредита controllerData = self.GetControllerData(controllerAddr) if controllerData["borrowed_amount"] != 0: @@ -3757,6 +3757,11 @@ def CreateLoanRequest(self, controllerAddr): return #end if + # Проверить наличие средств у ликвидного пула + if self.CalculateLoanAmount(min_loan, max_loan, max_interest) == -1: + raise Exception("CreateLoanRequest error: The liquid pool cannot issue the required amount of credit") + #end if + # Проверить хватает ли ставки валидатора min_amount, validator_amount = self.GetControllerRequiredBalanceForLoan(controllerAddr, max_loan, max_interest) if validator_amount < min_amount: @@ -3773,6 +3778,16 @@ def CreateLoanRequest(self, controllerAddr): self.WaitLoan(controllerAddr) #end define + def CalculateLoanAmount(self, min_loan, max_loan, max_interest): + liquid_pool_addr = self.GetLiquidPoolAddr() + cmd = f"runmethodfull {liquid_pool_addr} calculate_loan_amount {min_loan} {max_loan} {max_interest}" + result = self.liteClient.Run(cmd) + data = self.Result2List(result) + if data is None: + return + return result.pop() + #end define + def WaitLoan(self, controllerAddr): local.AddLog("start WaitLoan function", "debug") for i in range(10): diff --git a/mytonctrl.py b/mytonctrl.py index 8ae23805..4aa4baf1 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -75,6 +75,7 @@ def Init(argv): console.AddItem("get_controller_data", GetControllerData, local.Translate("_")) console.AddItem("deposit_to_controller", DepositToController, local.Translate("_")) console.AddItem("withdraw_from_controller", WithdrawFromController, local.Translate("_")) + console.AddItem("calculate_annual_controller_percentage", CalculateAnnualControllerPercentage, local.Translate("_")) # Process input parameters opts, args = getopt.getopt(argv,"hc:w:",["config=","wallets="]) @@ -1212,6 +1213,23 @@ def WithdrawFromController(args): ton.WithdrawFromController(controllerAddr, amount) #end define +def CalculateAnnualControllerPercentage(args): + try: + percentPerRound = float(args[0]) + except: + percentPerRound = ton.GetSettings("max_interest_percent") + config15 = ton.GetConfig(15) + roundPeriod = config15["validators_elected_for"] + rounds = 365 * 24 * 3600 / roundPeriod + yearInterest = (1 + percentPerRound / 100) * rounds + yearInterestPercent = round(yearInterest / 100, 2) + print("roundPeriod", roundPeriod) + print("rounds", rounds) + print("percentPerRound", percentPerRound) + print("yearInterest", yearInterest) + print(f"yearInterestPercent: {yearInterestPercent}%") +#end define + ### ### Start of the program From 6591e3633dd5ca218055db00419306f4961000c7 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 1 Jul 2023 16:36:39 +0300 Subject: [PATCH 008/236] bugfix --- mytoncore.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index f05efd96..5f1f239d 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3748,7 +3748,7 @@ def CreateLoanRequest(self, controllerAddr): min_loan = local.db.get("min_loan", 41000) max_loan = local.db.get("max_loan", 43000) max_interest_percent = local.db.get("max_interest_percent", 1.5) - max_interest = int(max_interest_percent/100*65536) + max_interest = int(max_interest_percent/100*16777216) # Проверить наличие старого кредита controllerData = self.GetControllerData(controllerAddr) @@ -3758,7 +3758,7 @@ def CreateLoanRequest(self, controllerAddr): #end if # Проверить наличие средств у ликвидного пула - if self.CalculateLoanAmount(min_loan, max_loan, max_interest) == -1: + if self.CalculateLoanAmount(min_loan, max_loan, max_interest) == '-0x1': raise Exception("CreateLoanRequest error: The liquid pool cannot issue the required amount of credit") #end if @@ -3779,13 +3779,19 @@ def CreateLoanRequest(self, controllerAddr): #end define def CalculateLoanAmount(self, min_loan, max_loan, max_interest): - liquid_pool_addr = self.GetLiquidPoolAddr() - cmd = f"runmethodfull {liquid_pool_addr} calculate_loan_amount {min_loan} {max_loan} {max_interest}" - result = self.liteClient.Run(cmd) - data = self.Result2List(result) - if data is None: - return - return result.pop() + data = dict() + data["address"] = liquid_pool_addr + data["method"] = "calculate_loan_amount" + data["stack"] = [ + ["num", min_loan*10**9], + ["num", max_loan*10**9], + ["num", max_interest], + ] + + url = "https://testnet.toncenter.com/api/v2/runGetMethod" + res = requests.post(url, json=data) + result = res.json().get("result").get("stack").pop().pop() + return result #end define def WaitLoan(self, controllerAddr): From a095227feb34b25c2a55bfefc213361306f268ff Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 1 Jul 2023 17:22:16 +0300 Subject: [PATCH 009/236] bugfix --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 5f1f239d..91e21eb2 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3780,7 +3780,7 @@ def CreateLoanRequest(self, controllerAddr): def CalculateLoanAmount(self, min_loan, max_loan, max_interest): data = dict() - data["address"] = liquid_pool_addr + data["address"] = self.GetLiquidPoolAddr() data["method"] = "calculate_loan_amount" data["stack"] = [ ["num", min_loan*10**9], From fde74608a77688994a078997f20cf49a6ed61ce5 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 2 Jul 2023 21:37:41 +0300 Subject: [PATCH 010/236] bugfix --- mytoncore.py | 38 ++++++++++++++++---------------------- mytonctrl.py | 18 +++++++++++++++--- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 91e21eb2..e73b2a7f 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3666,14 +3666,10 @@ def GetControllerAddress(self, controller_id): def CheckController(self, controllerAddr): local.AddLog("start CheckController function", "debug") - config34 = self.GetConfig34() controllerData = self.GetControllerData(controllerAddr) saveControllersAddr = local.db.get("controllersAddr", list()) if controllerData["approved"] != -1: raise Exception(f"CheckController error: controller not approved: {controllerAddr}") - if controllerData["borrowed_amount"] > 0 and config34["startWorkTime"] > controllerData["borrowing_time"]: - local.AddLog("CheckController warning: controller has loan. Return unused loan", "warning") - self.ReturnUnusedLoan(controllerAddr) if controllerAddr not in saveControllersAddr: raise Exception("CheckController error: controller is not up to date. Use new_controllers") #end define @@ -3750,13 +3746,6 @@ def CreateLoanRequest(self, controllerAddr): max_interest_percent = local.db.get("max_interest_percent", 1.5) max_interest = int(max_interest_percent/100*16777216) - # Проверить наличие старого кредита - controllerData = self.GetControllerData(controllerAddr) - if controllerData["borrowed_amount"] != 0: - local.AddLog("CreateLoanRequest info: loan already taken") - return - #end if - # Проверить наличие средств у ликвидного пула if self.CalculateLoanAmount(min_loan, max_loan, max_interest) == '-0x1': raise Exception("CreateLoanRequest error: The liquid pool cannot issue the required amount of credit") @@ -3764,7 +3753,7 @@ def CreateLoanRequest(self, controllerAddr): # Проверить хватает ли ставки валидатора min_amount, validator_amount = self.GetControllerRequiredBalanceForLoan(controllerAddr, max_loan, max_interest) - if validator_amount < min_amount: + if min_amount > validator_amount: raise Exception("CreateLoanRequest error: too_high_loan_request_amount") #end if @@ -3844,15 +3833,15 @@ def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlA return pubkey, fileName #end define - def ControllerUpdateValidatorSet(self): - local.AddLog("start ControllerUpdateValidatorSet function", "debug") + def ControllersUpdateValidatorSet(self): + local.AddLog("start ControllersUpdateValidatorSet function", "debug") controllers = self.GetControllers() for controller in controllers: - self.ControllerUpdateValidatorSetProcess(controller) + self.ControllerUpdateValidatorSet(controller) #end define - def ControllerUpdateValidatorSetProcess(self, controllerAddr): - local.AddLog("start ControllerUpdateValidatorSetProcess function", "debug") + def ControllerUpdateValidatorSet(self, controllerAddr): + local.AddLog("start ControllerUpdateValidatorSet function", "debug") wallet = self.GetValidatorWallet() controllerData = self.GetControllerData(controllerAddr) if controllerData is None: @@ -3868,21 +3857,26 @@ def ControllerUpdateValidatorSetProcess(self, controllerAddr): if (controllerData["state"] == 3 and controllerData["validator_set_changes_count"] < 2 and controllerData["validator_set_change_time"] < config34["startWorkTime"]): - self.ControllerProcessUpdateValidatorSet(controllerAddr, wallet) + self.ControllerUpdateValidatorSetProcess(controllerAddr, wallet) controllerData = self.GetControllerData(controllerAddr) if (returnedStake > 0 and controllerData["state"] == 3 and controllerData["validator_set_changes_count"] >= 2 and timeNow - controllerData["validator_set_change_time"] > controllerData["stake_held_for"] + 60): self.ControllerRecoverStake(controllerAddr) + controllerData = self.GetControllerData(controllerAddr) + if (controllerData["borrowed_amount"] > 0 and + controllerData["stake_amount_sent"] == 0 and + config34["startWorkTime"] > controllerData["borrowing_time"]): + self.ReturnUnusedLoan(controllerAddr) #end define - def ControllerProcessUpdateValidatorSet(self, controllerAddr, wallet): - local.AddLog("start ControllerProcessUpdateValidatorSet function", "debug") + def ControllerUpdateValidatorSetProcess(self, controllerAddr, wallet): + local.AddLog("start ControllerUpdateValidatorSetProcess function", "debug") fileName = self.contractsDir + "jetton_pool/fift-scripts/update_validator_hash.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.07) self.SendFile(resultFilePath, wallet) - local.AddLog("ControllerProcessUpdateValidatorSet completed") + local.AddLog("ControllerUpdateValidatorSetProcess completed") #end define def ControllerRecoverStake(self, controllerAddr): @@ -4236,7 +4230,7 @@ def Elections(ton): ton.RecoverStake() ton.ElectionEntry() elif useController == True: - ton.ControllerUpdateValidatorSet() + ton.ControllersUpdateValidatorSet() ton.RecoverStake() ton.ElectionEntry() else: diff --git a/mytonctrl.py b/mytonctrl.py index 4aa4baf1..4304974c 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -76,6 +76,8 @@ def Init(argv): console.AddItem("deposit_to_controller", DepositToController, local.Translate("_")) console.AddItem("withdraw_from_controller", WithdrawFromController, local.Translate("_")) console.AddItem("calculate_annual_controller_percentage", CalculateAnnualControllerPercentage, local.Translate("_")) + console.AddItem("controller_update_validator_set", ControllerUpdateValidatorSet, local.Translate("_")) + # Process input parameters opts, args = getopt.getopt(argv,"hc:w:",["config=","wallets="]) @@ -1152,15 +1154,15 @@ def DeletePool(args): ColorPrint("DeletePool - {green}OK{endc}") #end define -def UpdateValidatorSet(args): +def PoolUpdateValidatorSet(args): try: poolAddr = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} update_validator_set ") + ColorPrint("{red}Bad args. Usage:{endc} pool_update_validator_set ") return wallet = ton.GetValidatorWallet() ton.PoolUpdateValidatorSet(poolAddr, wallet) - ColorPrint("UpdateValidatorSet - {green}OK{endc}") + ColorPrint("PoolUpdateValidatorSet - {green}OK{endc}") #end define def NewControllers(args): @@ -1230,6 +1232,16 @@ def CalculateAnnualControllerPercentage(args): print(f"yearInterestPercent: {yearInterestPercent}%") #end define +def ControllerUpdateValidatorSet(args): + try: + controllerAddr = args[0] + except: + ColorPrint("{red}Bad args. Usage:{endc} controller_update_validator_set ") + return + ton.ControllerUpdateValidatorSet(controllerAddr) + ColorPrint("ControllerUpdateValidatorSet - {green}OK{endc}") +#end define + ### ### Start of the program From 121ff31bd530f5eed03941e2b33c26bd74dfa97c Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 5 Jul 2023 22:36:18 +0300 Subject: [PATCH 011/236] add `ton-http-api` service --- docs/en/controllers.md | 25 +++++++++++++------ docs/ru/controllers.md | 27 ++++++++++++++------- mytoncore.py | 2 +- mytoninstaller.py | 19 ++++++++------- scripts/ton_http_api_installer.sh | 40 +++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 25 deletions(-) create mode 100644 scripts/ton_http_api_installer.sh diff --git a/docs/en/controllers.md b/docs/en/controllers.md index 52150228..cfcb7853 100644 --- a/docs/en/controllers.md +++ b/docs/en/controllers.md @@ -19,12 +19,18 @@ 5. Transfer enough TON to the validator wallet address. -6. Set the liquid pool address, which will lend TON for validation: +6. Enable the ton-http-api service: + ``` + mytonctrl -> installer -> enable THA + ``` + Exit installer mode with `Ctrl+C` + +7. Set the liquid pool address, which will lend TON for validation: ``` set liquid_pool_addr ``` -7. Set the lending parameters that acceptable to you: +8. Set the lending parameters that acceptable to you: ``` set min_loan 41000 set max_loan 43000 @@ -36,13 +42,18 @@ * `43000` is the maximum loan amount we are willing to receive from the liquid pool, * `1.5` 1.5 is the maximum interest rate value for the liquid pool per validation cycle, which we have agreed upon. -8. Create two controllers with a single command: +9. Display the annual percentage of profit from the liquid pool: + ``` + calculate_annual_controller_percentage + ``` + +10. Create two controllers with a single command: ``` new_controllers ``` -9. Enter `controllers_list` to display the controller addresses: +11. Enter `controllers_list` to display the controller addresses: ``` controllers_list @@ -51,7 +62,7 @@ kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 ``` -10. Make a validator deposit in each controller: +12. Make a validator deposit in each controller: ``` @@ -62,9 +73,9 @@ deposit_to_controller kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN 10000 where `10000` TON is the deposit amount. -11. Get approval for the controllers. Each pool may have its own approval issuance policy, check with the operator. +13. Get approval for the controllers. Each pool may have its own approval issuance policy, check with the operator. -12. Set controller mode: +14. Set controller mode: ```bash set useController true diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md index aff65fd5..184bcc95 100644 --- a/docs/ru/controllers.md +++ b/docs/ru/controllers.md @@ -20,12 +20,18 @@ 5. Переведите достаточно TON на адрес кошелька валидатора. -6. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: +6. Включите ton-http-api службу: + ``` + mytonctrl -> installer -> enable THA + ``` + Выйдите из режима установщика сочетанием клавиш `Ctrl+C` + +7. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: ``` set liquid_pool_addr ``` -7. Задайте параметры кредитования, которые вам подходят: +8. Задайте параметры кредитования, которые вам подходят: ``` set min_loan 41000 set max_loan 43000 @@ -37,13 +43,18 @@ * `43000` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, * `1.5` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. -8. Создайте два контроллера одной командой: +9. Отобразите годовой процент прибыли от ликвидного пула: + ``` + calculate_annual_controller_percentage + ``` + +10. Создайте два контроллера одной командой: ``` new_controllers ``` -9. Введите `controllers_list` чтобы отобразить адреса контроллеров: +11. Введите `controllers_list` чтобы отобразить адреса контроллеров: ``` controllers_list @@ -52,7 +63,7 @@ kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 ``` -10. Совершите депозит валидатора в каждый контроллер: +12. Совершите депозит валидатора в каждый контроллер: ``` deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 @@ -61,9 +72,9 @@ где `10000` TON - это сумма депозита. -11. Получите аппрувал контроллеров. У каждого пула может быть своя политика выдачи аппруволов, уточняйте у оператора. +13. Получите аппрувал контроллеров. У каждого пула может быть своя политика выдачи аппруволов, уточняйте у оператора. -12. Активируйте режим работы контроллеров: +14. Активируйте режим работы контроллеров: ```bash set useController true @@ -79,4 +90,4 @@ 2. Дождитесь, когда оба ваших депозита вернутся от электора. -3. Следуйте инструкциям "Запуск валидатора в режиме работы контроллеров", начиная с **6-го шага**. \ No newline at end of file +3. Следуйте инструкциям "Запуск валидатора в режиме работы контроллеров", начиная с **6-го шага**. diff --git a/mytoncore.py b/mytoncore.py index e73b2a7f..cf533361 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3777,7 +3777,7 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): ["num", max_interest], ] - url = "https://testnet.toncenter.com/api/v2/runGetMethod" + url = "http://127.0.0.1:8801/runGetMethod" res = requests.post(url, json=data) result = res.json().get("result").get("stack").pop().pop() return result diff --git a/mytoninstaller.py b/mytoninstaller.py index e8bd9e58..e0101a55 100644 --- a/mytoninstaller.py +++ b/mytoninstaller.py @@ -31,7 +31,7 @@ def Init(): 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("enable", Enable, "Enable some function: 'FN' - Full node, 'VC' - Validator console, 'LS' - Liteserver, 'DS' - DHT-Server, 'JR' - jsonrpc, 'THA' - ton-http-api. 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") @@ -97,7 +97,7 @@ def Status(args): def Enable(args): name = args[0] user = local.buffer["user"] - if name == "PT": + if name == "enableTHA": CreateLocalConfigFile(args) args = ["python3", local.buffer["myPath"], "-u", user, "-e", "enable{name}".format(name=name)] RunAsRoot(args) @@ -195,8 +195,8 @@ def Event(name): DangerousRecoveryValidatorConfigFile() if name == "enableJR": EnableJsonRpc() - if name == "enablePT": - EnablePytonv3() + if name == "enableTHA": + EnableTonHttpApi() if name == "clc": ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] @@ -1000,14 +1000,15 @@ def EnableJsonRpc(): ColorPrint(text) #end define -def EnablePytonv3(): - local.AddLog("start EnablePytonv3 function", "debug") +def EnableTonHttpApi(): + local.AddLog("start EnableTonHttpApi function", "debug") user = local.buffer["user"] - exitCode = RunAsRoot(["bash", "/usr/src/mytonctrl/scripts/pytonv3installer.sh", "-u", user]) + runArgs = ["bash", "/usr/src/mytonctrl/scripts/ton_http_api_installer.sh", "-u", user] + exitCode = RunAsRoot(runArgs) if exitCode == 0: - text = "EnablePytonv3 - {green}OK{endc}" + text = "EnableTonHttpApi - {green}OK{endc}" else: - text = "EnablePytonv3 - {red}Error{endc}" + text = "EnableTonHttpApi - {red}Error{endc}" ColorPrint(text) #end define diff --git a/scripts/ton_http_api_installer.sh b/scripts/ton_http_api_installer.sh new file mode 100644 index 00000000..d76c13cc --- /dev/null +++ b/scripts/ton_http_api_installer.sh @@ -0,0 +1,40 @@ +#!/bin/bash +set -e + +# Проверить sudo +if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 +fi + +# Цвета +COLOR='\033[92m' +ENDC='\033[0m' + +# Установка компонентов python3 +pip3 install virtualenv + +# Подготовить папку с виртуальным окружением +echo -e "${COLOR}[1/4]${ENDC} Preparing the virtual environment" +venv_path="/opt/virtualenv/ton_http_api" +virtualenv ${venv_path} + +# Установка компонентов python3 +echo -e "${COLOR}[2/4]${ENDC} Installing required packages" +user=$(logname) +venv_pip3="${venv_path}/bin/pip3" +${venv_pip3} install ton-http-api +chown -R ${user}:${user} ${venv_path} + +# Прописать автозагрузку +echo -e "${COLOR}[3/4]${ENDC} Add to startup" +venv_ton_http_api="${venv_path}/bin/ton-http-api" +tonlib_path="/usr/bin/ton/tonlib/libtonlibjson.so" +ls_config="/usr/bin/ton/local.config.json" +cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import Add2Systemd; Add2Systemd(name='ton_http_api', user='${user}', start='${venv_ton_http_api} --host 127.0.0.1 --port 8801 --liteserver-config ${ls_config} --cdll-path ${tonlib_path}')" +python3 -c "${cmd}" +systemctl restart ton_http_api + +# Конец +echo -e "${COLOR}[4/4]${ENDC} ton_http_api service installation complete" +exit 0 From 518da3515a7a061bb0e07df3e355e7c33e828788 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 5 Jul 2023 22:41:50 +0300 Subject: [PATCH 012/236] update `controllers.md` --- docs/en/controllers.md | 2 +- docs/ru/controllers.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/en/controllers.md b/docs/en/controllers.md index cfcb7853..46b12c8a 100644 --- a/docs/en/controllers.md +++ b/docs/en/controllers.md @@ -23,7 +23,7 @@ ``` mytonctrl -> installer -> enable THA ``` - Exit installer mode with `Ctrl+C` + Exit installer mode with `Ctrl+D` 7. Set the liquid pool address, which will lend TON for validation: ``` diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md index 184bcc95..d3944549 100644 --- a/docs/ru/controllers.md +++ b/docs/ru/controllers.md @@ -24,7 +24,7 @@ ``` mytonctrl -> installer -> enable THA ``` - Выйдите из режима установщика сочетанием клавиш `Ctrl+C` + Выйдите из режима установщика сочетанием клавиш `Ctrl+D` 7. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: ``` From 8abb5fbaa7165a6ac0919322e29cc094a51883ac Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 9 Jul 2023 22:31:50 +0300 Subject: [PATCH 013/236] bugfix --- mytoncore.py | 2 +- mytoninstaller.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index cf533361..8152bb10 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3835,7 +3835,7 @@ def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlA def ControllersUpdateValidatorSet(self): local.AddLog("start ControllersUpdateValidatorSet function", "debug") - controllers = self.GetControllers() + controllers = local.db.get("controllersAddr") for controller in controllers: self.ControllerUpdateValidatorSet(controller) #end define diff --git a/mytoninstaller.py b/mytoninstaller.py index e0101a55..4b0ff5fc 100644 --- a/mytoninstaller.py +++ b/mytoninstaller.py @@ -97,7 +97,7 @@ def Status(args): def Enable(args): name = args[0] user = local.buffer["user"] - if name == "enableTHA": + if name == "THA": CreateLocalConfigFile(args) args = ["python3", local.buffer["myPath"], "-u", user, "-e", "enable{name}".format(name=name)] RunAsRoot(args) From 906cdf78e55d61be57ee854c1292cb60c6c54c6f Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 9 Jul 2023 22:43:20 +0300 Subject: [PATCH 014/236] withdraw_from_controller bugfix --- mytonctrl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mytonctrl.py b/mytonctrl.py index 4304974c..70ac139d 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -1209,7 +1209,6 @@ def WithdrawFromController(args): except: ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_controller ") return - ton.CheckController(controllerAddr) account = ton.GetAccount(controllerAddr) amount = account.balance-10.1 ton.WithdrawFromController(controllerAddr, amount) From a8abde06e47a305264676a24240ea8e921d8cf4c Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 9 Jul 2023 23:42:24 +0300 Subject: [PATCH 015/236] add error display when requested to ton-http-api --- mytoncore.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 8152bb10..1ee42392 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3648,6 +3648,7 @@ def CreateControllers(self): resultFilePath1 = self.SignBocWithWallet(wallet, fileName1, liquid_pool_addr, 1) self.SendFile(resultFilePath1, wallet) local.db["controllersAddr"] = self.GetControllers() + local.dbSave() #end define def GetControllerAddress(self, controller_id): @@ -3779,7 +3780,11 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): url = "http://127.0.0.1:8801/runGetMethod" res = requests.post(url, json=data) - result = res.json().get("result").get("stack").pop().pop() + res_data = res.json() + if res_data.get("ok") is False: + error = res_data.get("error") + raise Exception(error) + result = res_data.get("result").get("stack").pop().pop() return result #end define From aa91b52f0156c710067595f5e28fe837085c32ba Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 10 Jul 2023 12:49:28 +0300 Subject: [PATCH 016/236] ton_http_api installet bugfix --- mytoninstaller.py | 22 ++++++++++++++++------ scripts/ton_http_api_installer.sh | 4 ++-- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/mytoninstaller.py b/mytoninstaller.py index 4b0ff5fc..a97477d3 100644 --- a/mytoninstaller.py +++ b/mytoninstaller.py @@ -98,7 +98,7 @@ def Enable(args): name = args[0] user = local.buffer["user"] if name == "THA": - CreateLocalConfigFile(args) + CreateLocalConfigFile(args, localhost=True) args = ["python3", local.buffer["myPath"], "-u", user, "-e", "enable{name}".format(name=name)] RunAsRoot(args) #end define @@ -138,7 +138,7 @@ def GetInitBlock(): return initBlock #end define -def CreateLocalConfig(initBlock, localConfigPath=defaultLocalConfigPath): +def CreateLocalConfig(initBlock, localConfigPath=defaultLocalConfigPath, localhost=False): # dirty hack, but GetInitBlock() function uses the same technique from mytoncore import hex2base64 @@ -150,6 +150,9 @@ def CreateLocalConfig(initBlock, localConfigPath=defaultLocalConfigPath): # edit config liteServerConfig = GetLiteServerConfig() + if localhost is True: + liteServerConfig["ip"] = 2130706433 # 127.0.0.1 + localConfigPath = localConfigPath.replace("local", "localhost") data["liteservers"] = [liteServerConfig] data["validator"]["init_block"]["seqno"] = initBlock["seqno"] data["validator"]["init_block"]["root_hash"] = hex2base64(initBlock["rootHash"]) @@ -174,11 +177,15 @@ def PrintLiteServerConfig(args): print(text) #end define -def CreateLocalConfigFile(args): +def CreateLocalConfigFile(args, localhost=False): + if localhost is True: + event_name = "clcl" + else: + event_name = "clc" initBlock = GetInitBlock() initBlock_b64 = dict2b64(initBlock) user = local.buffer["user"] - args = ["python3", local.buffer["myPath"], "-u", user, "-e", "clc", "-i", initBlock_b64] + args = ["python3", local.buffer["myPath"], "-u", user, "-e", event_name, "-i", initBlock_b64] RunAsRoot(args) #end define @@ -197,11 +204,14 @@ def Event(name): EnableJsonRpc() if name == "enableTHA": EnableTonHttpApi() - if name == "clc": + if name in ["clc", "clcl"]: ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] initBlock = b642dict(initBlock_b64) - CreateLocalConfig(initBlock) + if name == "clcl": + CreateLocalConfig(initBlock, localhost=True) + else: + CreateLocalConfig(initBlock) #end define def General(): diff --git a/scripts/ton_http_api_installer.sh b/scripts/ton_http_api_installer.sh index d76c13cc..b27ef02a 100644 --- a/scripts/ton_http_api_installer.sh +++ b/scripts/ton_http_api_installer.sh @@ -30,8 +30,8 @@ chown -R ${user}:${user} ${venv_path} echo -e "${COLOR}[3/4]${ENDC} Add to startup" venv_ton_http_api="${venv_path}/bin/ton-http-api" tonlib_path="/usr/bin/ton/tonlib/libtonlibjson.so" -ls_config="/usr/bin/ton/local.config.json" -cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import Add2Systemd; Add2Systemd(name='ton_http_api', user='${user}', start='${venv_ton_http_api} --host 127.0.0.1 --port 8801 --liteserver-config ${ls_config} --cdll-path ${tonlib_path}')" +ls_config="/usr/bin/ton/localhost.config.json" +cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import Add2Systemd; Add2Systemd(name='ton_http_api', user='${user}', start='${venv_ton_http_api} --host 127.0.0.1 --port 8801 --liteserver-config ${ls_config} --cdll-path ${tonlib_path} --tonlib-keystore /tmp/tonlib_keystore/')" python3 -c "${cmd}" systemctl restart ton_http_api From 446a6a68904ca4930121c5c77712dd2517cd5f81 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:07:59 +0300 Subject: [PATCH 017/236] add SignElectionRequestWithController log --- mytoncore.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 1ee42392..108520ae 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3830,9 +3830,9 @@ def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlA fileName = self.tempDir + str(startWorkTime) + "_validator-query.boc" fiftScript = self.contractsDir + "jetton_pool/fift-scripts/controller-elect-signed.fif" args = [fiftScript, controllerAddr, startWorkTime, maxFactor, adnlAddr, validatorPubkey_b64, validatorSignature, fileName, stake] - print(f"args: {args}") + local.AddLog(f"SignElectionRequestWithController args: {args}", "debug") result = self.fift.Run(args) - print(f"result: {result}") + local.AddLog(f"SignElectionRequestWithController result: {result}", "debug") pubkey = Pars(result, "validator public key ", '\n') fileName = Pars(result, "Saved to file ", '\n') return pubkey, fileName From 318b6371cd7724cc8b36fd25fb33bb1c15ddb29e Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:44:57 +0300 Subject: [PATCH 018/236] update controller balance and stake difference --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 108520ae..31122d5f 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -1501,7 +1501,7 @@ def GetStake(self, account, args=None): if stake is None and usePool: stake = account.balance - 20 if stake is None and useController: - stake = account.balance - 30 + stake = account.balance - 50 if stake is None: sp = stakePercent / 100 if sp > 1 or sp < 0: From c484dca269f6233988c9cfcd686cb1414cfe3d7f Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 15 Jul 2023 15:33:15 +0300 Subject: [PATCH 019/236] add `add_controller` and `stop_controller` commands --- mytoncore.py | 79 +++++++++++++++++++++++++++++++++++++++++++++------- mytonctrl.py | 72 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 133 insertions(+), 18 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 31122d5f..7a89a00c 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3706,15 +3706,14 @@ def GetControllerRequiredBalanceForLoan(self, controllerAddr, credit, interest): return result #end define - def GetControllerLastSentStakeTime(self, addrB64): - controllerData = self.GetControllerData(addrB64) - return controllerData["stake_at"] - #end define - def IsControllerReadyToStake(self, addrB64): + stop_controllers_list = local.db.get("stop_controllers_list") + if stop_controllers_list is not None and addrB64 in stop_controllers_list: + return False now = GetTimestamp() config15 = self.GetConfig15() - lastSentStakeTime = self.GetControllerLastSentStakeTime(addrB64) + controllerData = self.GetControllerData(addrB64) + lastSentStakeTime = controllerData["stake_at"] stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] result = lastSentStakeTime + stakeFreezeDelay < now print(f"{addrB64}: {result}. {lastSentStakeTime}, {stakeFreezeDelay}, {now}") @@ -3815,7 +3814,15 @@ def DepositToController(self, controllerAddr, amount): #end define def WithdrawFromController(self, controllerAddr, amount): - local.AddLog("start WithdrawFromController function", "debug") + controllerData = self.GetControllerData(controllerAddr) + if controllerData["state"] == 0: + self.WithdrawFromControllerProcess(controllerAddr, amount) + else: + self.PendWithdrawFromController(controllerAddr, amount) + #end define + + def WithdrawFromControllerProcess(self, controllerAddr, amount): + local.AddLog("start WithdrawFromControllerProcess function", "debug") wallet = self.GetValidatorWallet() fiftScript = self.contractsDir + "jetton_pool/fift-scripts/withdraw-controller.fif" resultFilePath = self.tempDir + self.nodeName + wallet.name + "_withdraw_request.boc" @@ -3825,6 +3832,28 @@ def WithdrawFromController(self, controllerAddr, amount): self.SendFile(resultFilePath, wallet) #end define + def PendWithdrawFromController(self, controllerAddr, amount): + local.AddLog("start PendWithdrawFromController function", "debug") + controllerPendingWithdraws = self.GetControllerPendingWithdraws() + controllerPendingWithdraws[controllerAddr] = amount + local.dbSave() + #end define + + def HandleControllerPendingWithdraw(self, controllerPendingWithdraws, controllerAddr): + amount = controllerPendingWithdraws.get(controllerAddr) + self.WithdrawFromControllerProcess(controllerAddr, amount) + controllerPendingWithdraws.pop(controllerAddr) + #end define + + def GetControllerPendingWithdraws(self): + bname = "controllerPendingWithdraws" + controllerPendingWithdraws = local.db.get(bname) + if controllerPendingWithdraws is None: + controllerPendingWithdraws = dict() + local.db[bname] = controllerPendingWithdraws + return controllerPendingWithdraws + #end define + def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): local.AddLog("start SignElectionRequestWithController function", "debug") fileName = self.tempDir + str(startWorkTime) + "_validator-query.boc" @@ -3841,7 +3870,8 @@ def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlA def ControllersUpdateValidatorSet(self): local.AddLog("start ControllersUpdateValidatorSet function", "debug") controllers = local.db.get("controllersAddr") - for controller in controllers: + user_controllers_list = local.db.get("user_controllers_list", list()) + for controller in controllers + user_controllers_list: self.ControllerUpdateValidatorSet(controller) #end define @@ -3857,8 +3887,7 @@ def ControllerUpdateValidatorSet(self, controllerAddr): config34 = self.GetConfig34() fullElectorAddr = self.GetFullElectorAddr() returnedStake = self.GetReturnedStake(fullElectorAddr, controllerAddr) - print(f"Controller returnedStake: {returnedStake}") - pendingWithdraws = self.GetPendingWithdraws() + controllerPendingWithdraws = self.GetControllerPendingWithdraws() if (controllerData["state"] == 3 and controllerData["validator_set_changes_count"] < 2 and controllerData["validator_set_change_time"] < config34["startWorkTime"]): @@ -3874,6 +3903,8 @@ def ControllerUpdateValidatorSet(self, controllerAddr): controllerData["stake_amount_sent"] == 0 and config34["startWorkTime"] > controllerData["borrowing_time"]): self.ReturnUnusedLoan(controllerAddr) + if (controllerData["state"] == 0 and controllerAddr in controllerPendingWithdraws): + self.HandleControllerPendingWithdraw(controllerPendingWithdraws, controllerAddr) #end define def ControllerUpdateValidatorSetProcess(self, controllerAddr, wallet): @@ -3892,6 +3923,34 @@ def ControllerRecoverStake(self, controllerAddr): self.SendFile(resultFilePath, wallet) local.AddLog("ControllerRecoverStake completed") #end define + + def StopController(self, controllerAddr): + stop_controllers_list = local.db.get("stop_controllers_list") + if stop_controllers_list is None: + stop_controllers_list = list() + if controllerAddr not in stop_controllers_list: + stop_controllers_list.append(controllerAddr) + local.db["stop_controllers_list"] = stop_controllers_list + + user_controllers_list = local.db.get("user_controllers_list") + if user_controllers_list is not None and controllerAddr in user_controllers_list: + user_controllers_list.remove(controllerAddr) + local.dbSave() + #end define + + def AddController(self, controllerAddr): + user_controllers_list = local.db.get("user_controllers_list") + if user_controllers_list is None: + user_controllers_list = list() + if controllerAddr not in user_controllers_list: + user_controllers_list.append(controllerAddr) + local.db["user_controllers_list"] = user_controllers_list + + stop_controllers_list = local.db.get("stop_controllers_list") + if stop_controllers_list is not None and controllerAddr in stop_controllers_list: + stop_controllers_list.remove(controllerAddr) + local.dbSave() + #end define def GetNetworkName(self): mainnetValidatorsElectedFor = 65536 diff --git a/mytonctrl.py b/mytonctrl.py index 70ac139d..4cf9bec5 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -77,6 +77,9 @@ def Init(argv): console.AddItem("withdraw_from_controller", WithdrawFromController, local.Translate("_")) console.AddItem("calculate_annual_controller_percentage", CalculateAnnualControllerPercentage, local.Translate("_")) console.AddItem("controller_update_validator_set", ControllerUpdateValidatorSet, local.Translate("_")) + console.AddItem("stop_controller", StopController, local.Translate("_")) + console.AddItem("stop_and_withdraw_controller", StopAndWithdrawController, local.Translate("_")) + console.AddItem("add_controller", AddController, local.Translate("_")) # Process input parameters @@ -1171,15 +1174,31 @@ def NewControllers(args): #end define def PrintControllersList(args): - table = list() - table += [["Address", "Status", "Balance"]] controllers = ton.GetControllers() + controllersAddr = ton.GetSettings("controllersAddr") + user_controllers_list = ton.GetSettings("user_controllers_list") if (controllers is None or len(controllers) == 0): print("No data") return + PrintControllersListProcess(controllers) + if controllers != controllersAddr: + print() + print("old controllers:") + PrintControllersListProcess(controllersAddr) + if user_controllers_list is not None and len(user_controllers_list) > 0: + print() + print("user controllers:") + PrintControllersListProcess(user_controllers_list) +#end define + +def PrintControllersListProcess(controllers): + table = list() + table += [["Address", "Status", "Balance", "Approved", "State"]] for controllerAddr in controllers: account = ton.GetAccount(controllerAddr) - table += [[controllerAddr, account.status, account.balance]] + controllerData = ton.GetControllerData(controllerAddr) + approved = True if controllerData["approved"] == -1 else False + table += [[controllerAddr, account.status, account.balance, approved, controllerData["state"]]] PrintTable(table) #end define @@ -1189,8 +1208,8 @@ def GetControllerData(args): except: ColorPrint("{red}Bad args. Usage:{endc} get_controller_data ") return - data = ton.GetControllerData(controllerAddr) - print(f"ControllerData: {data}") + controllerData = ton.GetControllerData(controllerAddr) + print(json.dumps(controllerData, indent=4)) #end define def DepositToController(args): @@ -1206,11 +1225,13 @@ def DepositToController(args): def WithdrawFromController(args): try: controllerAddr = args[0] + amount = GetItemFromList(args, 1) except: - ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_controller ") + ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") return - account = ton.GetAccount(controllerAddr) - amount = account.balance-10.1 + if amount is None: + account = ton.GetAccount(controllerAddr) + amount = account.balance-10.1 ton.WithdrawFromController(controllerAddr, amount) #end define @@ -1241,6 +1262,41 @@ def ControllerUpdateValidatorSet(args): ColorPrint("ControllerUpdateValidatorSet - {green}OK{endc}") #end define +def StopController(args): + try: + controllerAddr = args[0] + except: + ColorPrint("{red}Bad args. Usage:{endc} stop_controller ") + return + ton.StopController(controllerAddr) + ColorPrint("StopController - {green}OK{endc}") +#end define + +def StopAndWithdrawController(args): + try: + controllerAddr = args[0] + amount = GetItemFromList(args, 1) + except: + ColorPrint("{red}Bad args. Usage:{endc} stop_and_withdraw_controller [amount]") + return + if amount is None: + account = ton.GetAccount(controllerAddr) + amount = account.balance-10.1 + ton.StopController(controllerAddr) + ton.WithdrawFromController(controllerAddr, amount) + ColorPrint("StopAndWithdrawController - {green}OK{endc}") +#end define + +def AddController(args): + try: + controllerAddr = args[0] + except: + ColorPrint("{red}Bad args. Usage:{endc} add_controller ") + return + ton.AddController(controllerAddr) + ColorPrint("AddController - {green}OK{endc}") +#end define + ### ### Start of the program From a8cd483508ca48fadbf72bac285d617304537012 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 15 Jul 2023 21:42:17 +0300 Subject: [PATCH 020/236] add `check_liquid_pool` command --- mytoncore.py | 42 ++++++++++++++++++++++++++++++++++++++++-- mytonctrl.py | 9 ++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 7a89a00c..b3ed3d38 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -760,8 +760,16 @@ def GetWalletVersionFromHash(self, inputHash): arr["v3r2"] = "8a6d73bdd8704894f17d8c76ce6139034b8a51b1802907ca36283417798a219b" arr["v4"] = "7ae380664c513769eaa5c94f9cd5767356e3f7676163baab66a4b73d5edab0e5" arr["hv1"] = "fc8e48ed7f9654ba76757f52cc6031b2214c02fab9e429ffa0340f5575f9f29c" - for version, hash in arr.items(): - if hash == inputHash: + arr["liquid_pool_r1"] = "82bc5760719c34395f80df76c42dc5d287f08f6562c643601ebed6944302dcc2" + arr["liquid_pool_r2"] = "95abec0a66ac63b0fbcf28466eb8240ddcd88f97300691511d9c9975d5521e4a" + arr["liquid_pool_r3"] = "22a023bc75b649ff2b5b183cd0d34cd413e6e27ee6d6ad0787f75ad39787ed4e" + arr["liquid_pool_r4"] = "77282b45fd7cfc72ca68fe97af33ad10078730ceaf55e20534c9526c48d602d2" + arr["controller_r1"] = "0949cf92963dd27bb1e6bf76487807f20409131b6110acbc18b7fbb90280ccf0" + arr["controller_r2"] = "01118b9553151fb9bc81704a4b3e0fc7b899871a527d44435a51574806863e2c" + arr["controller_r3"] = "e4d8ce8ff7b4b60c76b135eb8702ce3c86dc133fcee7d19c7aa18f71d9d91438" + arr["controller_r4"] = "dec125a4850c4ba24668d84252b04c6ad40abf5c9d413a429b56bfff09ea25d4" + for version, codeHash in arr.items(): + if codeHash == inputHash: return version #end for #end define @@ -3089,6 +3097,8 @@ def GetDestinationAddr(self, destination): #end define def AddrFull2AddrB64(self, addrFull, bounceable=True): + if addrFull is None or "None" in addrFull: + return testnet = self.IsTestnet() buff = addrFull.split(':') workchain = int(buff[0]) @@ -3951,6 +3961,34 @@ def AddController(self, controllerAddr): stop_controllers_list.remove(controllerAddr) local.dbSave() #end define + + def CheckLiquidPool(self): + liquid_pool_addr = self.GetLiquidPoolAddr() + account = self.GetAccount(liquid_pool_addr) + history = self.GetAccountHistory(account, 5000) + addrs_list = list() + for message in history: + if message.srcAddr is None or message.value is None: + continue + srcAddrFull = f"{message.srcWorkchain}:{message.srcAddr}" + destAddFull = f"{message.destWorkchain}:{message.destAddr}" + if srcAddrFull == account.addrFull: + fromto = destAddFull + else: + fromto = srcAddrFull + fromto = self.AddrFull2AddrB64(fromto) + if fromto not in addrs_list: + addrs_list.append(fromto) + #end for + + for controllerAddr in addrs_list: + account = self.GetAccount(controllerAddr) + version = self.GetWalletVersionFromHash(account.codeHash) + if version is None or "controller" not in version: + continue + print(f"check controller: {controllerAddr}") + self.ControllerUpdateValidatorSet(controllerAddr) + #end define def GetNetworkName(self): mainnetValidatorsElectedFor = 65536 diff --git a/mytonctrl.py b/mytonctrl.py index 4cf9bec5..a3e7e7bc 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -80,6 +80,7 @@ def Init(argv): console.AddItem("stop_controller", StopController, local.Translate("_")) console.AddItem("stop_and_withdraw_controller", StopAndWithdrawController, local.Translate("_")) console.AddItem("add_controller", AddController, local.Translate("_")) + console.AddItem("check_liquid_pool", CheckLiquidPool, local.Translate("_")) # Process input parameters @@ -679,6 +680,7 @@ def ViewAccountStatus(args): statusTable += [[addrB64, account.status, version, account.balance]] historyTable = GetHistoryTable(addrB64, 10) PrintTable(statusTable) + ColorPrint("{yellow}codeHash: " + account.codeHash + "{endc}") print() PrintTable(historyTable) #end define @@ -702,7 +704,7 @@ def GetHistoryTable(addr, limit): typeText = ColorText("{red}{bold}{endc}") table += [["Time", typeText, "Coins", "From/To"]] for message in history: - if message.srcAddr is None: + if message.srcAddr is None or message.value is None: continue srcAddrFull = f"{message.srcWorkchain}:{message.srcAddr}" destAddFull = f"{message.destWorkchain}:{message.destAddr}" @@ -1297,6 +1299,11 @@ def AddController(args): ColorPrint("AddController - {green}OK{endc}") #end define +def CheckLiquidPool(args): + ton.CheckLiquidPool() + ColorPrint("CheckLiquidPool - {green}OK{endc}") +#end define + ### ### Start of the program From 987b09e00493a7882153f9ff14224e91fb543b3c Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 18 Jul 2023 12:08:05 +0300 Subject: [PATCH 021/236] Add seamless transition to new controllers This method is not completely seamless, as it only automatically returns the stake to the validator's account. The validator will still need to create new controllers, add a stake to them, and wait for approval from the liquid pool. --- mytoncore.py | 19 +++++++++++++++++-- mytonctrl.py | 3 --- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index b3ed3d38..2a825fd2 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3657,6 +3657,15 @@ def CreateControllers(self): time.sleep(10) resultFilePath1 = self.SignBocWithWallet(wallet, fileName1, liquid_pool_addr, 1) self.SendFile(resultFilePath1, wallet) + + # Доработать старые контроллеры + old_controllers = local.db.get("controllersAddr". list()) + local.db["old_controllers"] = old_controllers.copy() + for controllerAddr in old_controllers + self.WithdrawFromController(controllerAddr) + #end for + + # Сохранить новые контроллеры local.db["controllersAddr"] = self.GetControllers() local.dbSave() #end define @@ -3823,7 +3832,7 @@ def DepositToController(self, controllerAddr, amount): self.SendFile(resultFilePath, wallet) #end define - def WithdrawFromController(self, controllerAddr, amount): + def WithdrawFromController(self, controllerAddr, amount=None): controllerData = self.GetControllerData(controllerAddr) if controllerData["state"] == 0: self.WithdrawFromControllerProcess(controllerAddr, amount) @@ -3833,6 +3842,11 @@ def WithdrawFromController(self, controllerAddr, amount): def WithdrawFromControllerProcess(self, controllerAddr, amount): local.AddLog("start WithdrawFromControllerProcess function", "debug") + if amount is None: + account = self.GetAccount(controllerAddr) + amount = account.balance-10.1 + #end if + wallet = self.GetValidatorWallet() fiftScript = self.contractsDir + "jetton_pool/fift-scripts/withdraw-controller.fif" resultFilePath = self.tempDir + self.nodeName + wallet.name + "_withdraw_request.boc" @@ -3881,7 +3895,8 @@ def ControllersUpdateValidatorSet(self): local.AddLog("start ControllersUpdateValidatorSet function", "debug") controllers = local.db.get("controllersAddr") user_controllers_list = local.db.get("user_controllers_list", list()) - for controller in controllers + user_controllers_list: + old_controllers = local.db.get("old_controllers", list()) + for controller in controllers + user_controllers_list + old_controllers: self.ControllerUpdateValidatorSet(controller) #end define diff --git a/mytonctrl.py b/mytonctrl.py index a3e7e7bc..9ee62a1d 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -1231,9 +1231,6 @@ def WithdrawFromController(args): except: ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") return - if amount is None: - account = ton.GetAccount(controllerAddr) - amount = account.balance-10.1 ton.WithdrawFromController(controllerAddr, amount) #end define From da61de8088b0018b033d5852fa0f4bb3c96def11 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 18 Jul 2023 16:51:01 +0300 Subject: [PATCH 022/236] Update mytoncore.py --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 2a825fd2..84e31ab1 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3661,7 +3661,7 @@ def CreateControllers(self): # Доработать старые контроллеры old_controllers = local.db.get("controllersAddr". list()) local.db["old_controllers"] = old_controllers.copy() - for controllerAddr in old_controllers + for controllerAddr in old_controllers: self.WithdrawFromController(controllerAddr) #end for From 3dfd068b9ffbc3be67718d236e262c501cbc9aa2 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 18 Jul 2023 20:55:04 +0300 Subject: [PATCH 023/236] controllerData bugfix --- mytoncore.py | 4 ++++ mytonctrl.py | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 84e31ab1..4080ffc5 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3688,6 +3688,8 @@ def CheckController(self, controllerAddr): local.AddLog("start CheckController function", "debug") controllerData = self.GetControllerData(controllerAddr) saveControllersAddr = local.db.get("controllersAddr", list()) + if controllerData is None: + raise Exception(f"CheckController error: controller not initialized. Use new_controllers") if controllerData["approved"] != -1: raise Exception(f"CheckController error: controller not approved: {controllerAddr}") if controllerAddr not in saveControllersAddr: @@ -3732,6 +3734,8 @@ def IsControllerReadyToStake(self, addrB64): now = GetTimestamp() config15 = self.GetConfig15() controllerData = self.GetControllerData(addrB64) + if controllerData is None: + return lastSentStakeTime = controllerData["stake_at"] stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] result = lastSentStakeTime + stakeFreezeDelay < now diff --git a/mytonctrl.py b/mytonctrl.py index 9ee62a1d..c1123730 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -1199,8 +1199,9 @@ def PrintControllersListProcess(controllers): for controllerAddr in controllers: account = ton.GetAccount(controllerAddr) controllerData = ton.GetControllerData(controllerAddr) - approved = True if controllerData["approved"] == -1 else False - table += [[controllerAddr, account.status, account.balance, approved, controllerData["state"]]] + approved = True if controllerData and controllerData["approved"] == -1 else False + state = controllerData["state"] if controllerData else None + table += [[controllerAddr, account.status, account.balance, approved, state]] PrintTable(table) #end define From e421d4824f234a130d8fc28be0833bb662e8a52e Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 19 Jul 2023 14:28:29 +0300 Subject: [PATCH 024/236] add error text for controller --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 4080ffc5..96d90642 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3735,7 +3735,7 @@ def IsControllerReadyToStake(self, addrB64): config15 = self.GetConfig15() controllerData = self.GetControllerData(addrB64) if controllerData is None: - return + raise Exception(f"IsControllerReadyToStake error: controller not initialized. Use new_controllers") lastSentStakeTime = controllerData["stake_at"] stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] result = lastSentStakeTime + stakeFreezeDelay < now From 47055a1558c9a37ca7dd0d6e740a1c03dc3c9dca Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 19 Jul 2023 17:00:47 +0300 Subject: [PATCH 025/236] bugfix --- mytoncore.py | 27 ++++++++++++++++----------- mytonctrl.py | 7 ++++--- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 96d90642..9e8bdcd7 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -1718,7 +1718,7 @@ def PoolUpdateValidatorSet(self, pool, wallet): poolData = self.GetPoolData(poolAddr) if poolData is None: return - #en if + #end if timeNow = int(time.time()) config34 = self.GetConfig34() @@ -3642,6 +3642,12 @@ def GetLiquidPoolAddr(self): #end define def CreateControllers(self): + new_controllers = self.GetControllers() + old_controllers = local.db.get("controllersAddr", list()) + if new_controllers == old_controllers: + return + #end if + local.AddLog("start CreateControllers function", "debug") wallet = self.GetValidatorWallet() liquid_pool_addr = self.GetLiquidPoolAddr() @@ -3658,15 +3664,9 @@ def CreateControllers(self): resultFilePath1 = self.SignBocWithWallet(wallet, fileName1, liquid_pool_addr, 1) self.SendFile(resultFilePath1, wallet) - # Доработать старые контроллеры - old_controllers = local.db.get("controllersAddr". list()) - local.db["old_controllers"] = old_controllers.copy() - for controllerAddr in old_controllers: - self.WithdrawFromController(controllerAddr) - #end for - # Сохранить новые контроллеры - local.db["controllersAddr"] = self.GetControllers() + local.db["old_controllers"] = old_controllers + local.db["controllersAddr"] = new_controllers local.dbSave() #end define @@ -3845,12 +3845,14 @@ def WithdrawFromController(self, controllerAddr, amount=None): #end define def WithdrawFromControllerProcess(self, controllerAddr, amount): - local.AddLog("start WithdrawFromControllerProcess function", "debug") if amount is None: account = self.GetAccount(controllerAddr) amount = account.balance-10.1 + if amount < 3: + return #end if + local.AddLog("start WithdrawFromControllerProcess function", "debug") wallet = self.GetValidatorWallet() fiftScript = self.contractsDir + "jetton_pool/fift-scripts/withdraw-controller.fif" resultFilePath = self.tempDir + self.nodeName + wallet.name + "_withdraw_request.boc" @@ -3907,10 +3909,11 @@ def ControllersUpdateValidatorSet(self): def ControllerUpdateValidatorSet(self, controllerAddr): local.AddLog("start ControllerUpdateValidatorSet function", "debug") wallet = self.GetValidatorWallet() + controllers = self.GetControllers() controllerData = self.GetControllerData(controllerAddr) if controllerData is None: return - #en if + #end if timeNow = int(time.time()) config34 = self.GetConfig34() @@ -3934,6 +3937,8 @@ def ControllerUpdateValidatorSet(self, controllerAddr): self.ReturnUnusedLoan(controllerAddr) if (controllerData["state"] == 0 and controllerAddr in controllerPendingWithdraws): self.HandleControllerPendingWithdraw(controllerPendingWithdraws, controllerAddr) + if controllerAddr not in controllers: + self.WithdrawFromController(controllerAddr) #end define def ControllerUpdateValidatorSetProcess(self, controllerAddr, wallet): diff --git a/mytonctrl.py b/mytonctrl.py index c1123730..fce1691f 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -70,7 +70,8 @@ def Init(argv): console.AddItem("withdraw_from_pool", WithdrawFromPool, local.Translate("withdraw_from_pool_cmd")) console.AddItem("delete_pool", DeletePool, local.Translate("delete_pool_cmd")) - console.AddItem("new_controllers", NewControllers, local.Translate("_")) + console.AddItem("create_controllers", CreateControllers, local.Translate("_")) + console.AddItem("update_controllers", CreateControllers, local.Translate("_")) console.AddItem("controllers_list", PrintControllersList, local.Translate("_")) console.AddItem("get_controller_data", GetControllerData, local.Translate("_")) console.AddItem("deposit_to_controller", DepositToController, local.Translate("_")) @@ -1170,9 +1171,9 @@ def PoolUpdateValidatorSet(args): ColorPrint("PoolUpdateValidatorSet - {green}OK{endc}") #end define -def NewControllers(args): +def CreateControllers(args): ton.CreateControllers() - ColorPrint("NewControllers - {green}OK{endc}") + ColorPrint("CreateControllers - {green}OK{endc}") #end define def PrintControllersList(args): From 2c5217b940b7c90ab040ac0a761673e14239ba94 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 19 Jul 2023 20:47:43 +0300 Subject: [PATCH 026/236] rename controllers vars --- mytoncore.py | 42 ++++++++++++++++++++---------------------- mytonctrl.py | 23 +++++++++++++++-------- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 9e8bdcd7..48d67506 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3643,7 +3643,7 @@ def GetLiquidPoolAddr(self): def CreateControllers(self): new_controllers = self.GetControllers() - old_controllers = local.db.get("controllersAddr", list()) + old_controllers = local.db.get("using_controllers", list()) if new_controllers == old_controllers: return #end if @@ -3666,7 +3666,7 @@ def CreateControllers(self): # Сохранить новые контроллеры local.db["old_controllers"] = old_controllers - local.db["controllersAddr"] = new_controllers + local.db["using_controllers"] = new_controllers local.dbSave() #end define @@ -3687,12 +3687,12 @@ def GetControllerAddress(self, controller_id): def CheckController(self, controllerAddr): local.AddLog("start CheckController function", "debug") controllerData = self.GetControllerData(controllerAddr) - saveControllersAddr = local.db.get("controllersAddr", list()) + using_controllers = local.db.get("using_controllers", list()) if controllerData is None: raise Exception(f"CheckController error: controller not initialized. Use new_controllers") if controllerData["approved"] != -1: raise Exception(f"CheckController error: controller not approved: {controllerAddr}") - if controllerAddr not in saveControllersAddr: + if controllerAddr not in using_controllers: raise Exception("CheckController error: controller is not up to date. Use new_controllers") #end define @@ -3720,11 +3720,9 @@ def GetControllerRequiredBalanceForLoan(self, controllerAddr, credit, interest): data = self.Result2List(result) if data is None: return - result_vars = ["min_amount", "validator_amount"] - result = dict() - for name in result_vars: - result[name] = data.pop(0) - return result + min_amount = data[0] + validator_amount = data[1] + return min_amount, validator_amount #end define def IsControllerReadyToStake(self, addrB64): @@ -3777,7 +3775,7 @@ def CreateLoanRequest(self, controllerAddr): # Проверить хватает ли ставки валидатора min_amount, validator_amount = self.GetControllerRequiredBalanceForLoan(controllerAddr, max_loan, max_interest) if min_amount > validator_amount: - raise Exception("CreateLoanRequest error: too_high_loan_request_amount") + raise Exception("CreateLoanRequest error: Validator stake is too low. Use deposit_to_controller") #end if wallet = self.GetValidatorWallet() @@ -3899,10 +3897,10 @@ def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlA def ControllersUpdateValidatorSet(self): local.AddLog("start ControllersUpdateValidatorSet function", "debug") - controllers = local.db.get("controllersAddr") - user_controllers_list = local.db.get("user_controllers_list", list()) + using_controllers = local.db.get("using_controllers") + user_controllers = local.db.get("user_controllers", list()) old_controllers = local.db.get("old_controllers", list()) - for controller in controllers + user_controllers_list + old_controllers: + for controller in using_controllers + user_controllers + old_controllers: self.ControllerUpdateValidatorSet(controller) #end define @@ -3966,19 +3964,19 @@ def StopController(self, controllerAddr): stop_controllers_list.append(controllerAddr) local.db["stop_controllers_list"] = stop_controllers_list - user_controllers_list = local.db.get("user_controllers_list") - if user_controllers_list is not None and controllerAddr in user_controllers_list: - user_controllers_list.remove(controllerAddr) + user_controllers = local.db.get("user_controllers") + if user_controllers is not None and controllerAddr in user_controllers: + user_controllers.remove(controllerAddr) local.dbSave() #end define def AddController(self, controllerAddr): - user_controllers_list = local.db.get("user_controllers_list") - if user_controllers_list is None: - user_controllers_list = list() - if controllerAddr not in user_controllers_list: - user_controllers_list.append(controllerAddr) - local.db["user_controllers_list"] = user_controllers_list + user_controllers = local.db.get("user_controllers") + if user_controllers is None: + user_controllers = list() + if controllerAddr not in user_controllers: + user_controllers.append(controllerAddr) + local.db["user_controllers"] = user_controllers stop_controllers_list = local.db.get("stop_controllers_list") if stop_controllers_list is not None and controllerAddr in stop_controllers_list: diff --git a/mytonctrl.py b/mytonctrl.py index fce1691f..a70db3c6 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -117,6 +117,10 @@ def Init(argv): def PreUp(): CheckMytonctrlUpdate() # CheckTonUpdate() + buff = ton.GetSettings("using_controllers") + if buff is None or len(buff) == 0: + using_controllers = ton.GetSettings("controllersAddr") + ton.SetSettings("using_controllers", using_controllers) #end define def Installer(args): @@ -1177,17 +1181,20 @@ def CreateControllers(args): #end define def PrintControllersList(args): - controllers = ton.GetControllers() - controllersAddr = ton.GetSettings("controllersAddr") + new_controllers = ton.GetControllers() + using_controllers = ton.GetSettings("using_controllers") + old_controllers = ton.GetSettings("old_controllers") user_controllers_list = ton.GetSettings("user_controllers_list") - if (controllers is None or len(controllers) == 0): - print("No data") - return - PrintControllersListProcess(controllers) - if controllers != controllersAddr: + print("using controllers:") + PrintControllersListProcess(using_controllers) + if new_controllers != using_controllers: + print() + print("new controllers:") + PrintControllersListProcess(new_controllers) + if old_controllers is not None and len(old_controllers) > 0: print() print("old controllers:") - PrintControllersListProcess(controllersAddr) + PrintControllersListProcess(old_controllers) if user_controllers_list is not None and len(user_controllers_list) > 0: print() print("user controllers:") From 42976f56f3cfbdf450f0c481a744b6d79215aa5d Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 27 Jul 2023 13:35:57 +0300 Subject: [PATCH 027/236] fix a defaulted loan --- mytoncore.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 48d67506..f352b8e8 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3766,6 +3766,13 @@ def CreateLoanRequest(self, controllerAddr): max_loan = local.db.get("max_loan", 43000) max_interest_percent = local.db.get("max_interest_percent", 1.5) max_interest = int(max_interest_percent/100*16777216) + + # Проверить наличие действующего кредита + controllerData = self.GetControllerData(controllerAddr) + if controllerData["borrowed_amount"] > 0: + local.AddLog("CreateLoanRequest warning: past loan found", "warning") + return + #end define # Проверить наличие средств у ликвидного пула if self.CalculateLoanAmount(min_loan, max_loan, max_interest) == '-0x1': @@ -3930,7 +3937,6 @@ def ControllerUpdateValidatorSet(self, controllerAddr): self.ControllerRecoverStake(controllerAddr) controllerData = self.GetControllerData(controllerAddr) if (controllerData["borrowed_amount"] > 0 and - controllerData["stake_amount_sent"] == 0 and config34["startWorkTime"] > controllerData["borrowing_time"]): self.ReturnUnusedLoan(controllerAddr) if (controllerData["state"] == 0 and controllerAddr in controllerPendingWithdraws): From ac484ec0be559e3605c48c2d53e24690c5e91723 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 2 Aug 2023 22:07:46 +0300 Subject: [PATCH 028/236] bugfix --- mytoncore.py | 3 ++- mytonctrl.py | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index f352b8e8..442db6e0 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3936,7 +3936,8 @@ def ControllerUpdateValidatorSet(self, controllerAddr): timeNow - controllerData["validator_set_change_time"] > controllerData["stake_held_for"] + 60): self.ControllerRecoverStake(controllerAddr) controllerData = self.GetControllerData(controllerAddr) - if (controllerData["borrowed_amount"] > 0 and + if (controllerData["state"] == 0 and + controllerData["borrowed_amount"] > 0 and config34["startWorkTime"] > controllerData["borrowing_time"]): self.ReturnUnusedLoan(controllerAddr) if (controllerData["state"] == 0 and controllerAddr in controllerPendingWithdraws): diff --git a/mytonctrl.py b/mytonctrl.py index a70db3c6..33cb5596 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -117,10 +117,10 @@ def Init(argv): def PreUp(): CheckMytonctrlUpdate() # CheckTonUpdate() - buff = ton.GetSettings("using_controllers") - if buff is None or len(buff) == 0: - using_controllers = ton.GetSettings("controllersAddr") - ton.SetSettings("using_controllers", using_controllers) + usePool = ton.GetSettings("usePool") + useController = ton.GetSettings("useController") + if usePool == True and useController == True: + local.AddLog("usePool == True and useController == True", "error") #end define def Installer(args): From b3be3007cd686f79092b30113c7309cf2f8a2eee Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 21 Aug 2023 13:21:49 +0300 Subject: [PATCH 029/236] WithdrawFromControllerProcess bugfix --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 442db6e0..a4ff4bb8 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3853,7 +3853,7 @@ def WithdrawFromControllerProcess(self, controllerAddr, amount): if amount is None: account = self.GetAccount(controllerAddr) amount = account.balance-10.1 - if amount < 3: + if int(amount) < 3: return #end if From a82ffd8c88507dd068874541a265fb0da686373a Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 14 Sep 2023 19:14:53 +0300 Subject: [PATCH 030/236] update `mypylib` --- README.Ru.md | 20 +- README.md | 105 ++++-- mypyconsole | 2 +- mypylib | 2 +- mytoncore.py | 878 +++++++++++++++++++--------------------------- mytonctrl.py | 636 ++++++++++++++++++--------------- mytoninstaller.py | 595 +++++++++++++++---------------- translate.json | 263 +++++++++----- 8 files changed, 1250 insertions(+), 1251 deletions(-) diff --git a/README.Ru.md b/README.Ru.md index 34ebe4e2..91acd3d9 100644 --- a/README.Ru.md +++ b/README.Ru.md @@ -1,6 +1,6 @@ ## Что это Данная консольная программа является оберткой над `fift`, `lite-client` и `validator-engine-console`. Она была создана для облегчения управления кошельками, доменами и валидатором на операционной системе `Linux`. -![](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/mytonctrl-status_ru.png) +![](screens/mytonctrl-status_ru.png) ## Функционал - [x] Показать статус сети TON @@ -42,14 +42,16 @@ - [x] Отправлять статистику валидатора на https://toncenter.com ## Список проверенных операционных систем -``` -Ubuntu 16.04 LTS (Xenial Xerus) - Error: TON compilation error -Ubuntu 18.04 LTS (Bionic Beaver) - OK -Ubuntu 20.04 LTS (Focal Fossa) - OK -Debian 8 - Error: Unable to locate package libgsl-dev -Debian 9 - Error: TON compilation error -Debian 10 - OK -``` +| Operating System | Status | +|-------------------------------|----------------------------| +| Ubuntu 16.04 LTS (Xenial Xerus) | Error: TON compilation error | +| Ubuntu 18.04 LTS (Bionic Beaver) | OK | +| Ubuntu 20.04 LTS (Focal Fossa) | OK | +| Ubuntu 22.04 LTS (Jammy Jellyfish) | OK | +| Debian 8 | Error: Unable to locate package libgsl-dev | +| Debian 9 | Error: TON compilation error | +| Debian 10 | OK | + ## Описание установочных скриптов - `toninstaller.sh` - Данный скрипт клонирует исходники `TON` и `mytonctrl` в папки `/usr/src/ton` и `/usr/src/mytonctrl`, компилирует программы из исходников и прописывает их в `/usr/bin/`. diff --git a/README.md b/README.md index b159e703..a41b61d4 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,34 @@ -[Данный текст доступен на русском языке.](https://github.com/ton-blockchain/mytonctrl/blob/master/README.Ru.md) +![GitHub stars](https://img.shields.io/github/stars/ton-blockchain/mytonctrl?style=flat-square&logo=github) ![GitHub forks](https://img.shields.io/github/forks/ton-blockchain/mytonctrl?style=flat-square&logo=github) ![GitHub issues](https://img.shields.io/github/issues/ton-blockchain/mytonctrl?style=flat-square&logo=github) ![GitHub pull requests](https://img.shields.io/github/issues-pr/ton-blockchain/mytonctrl?style=flat-square&logo=github) ![GitHub last commit](https://img.shields.io/github/last-commit/ton-blockchain/mytonctrl?style=flat-square&logo=github) ![GitHub license](https://img.shields.io/github/license/ton-blockchain/mytonctrl?style=flat-square&logo=github) -## What is it? -This console is a wrapper over `fift`,`lite-client` and `validator-engine-console`. It was created to facilitate wallet, domain and validator management on Linux OS. + +# MyTonCtrl +[Данный текст доступен на русском языке.](README.Ru.md) -![](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/mytonctrl-status.png) + +## Contents -## Functionality +- [What is MyTonCtrl?](#what-is-myttonctrl) +- [Functionality](#functionality) + - [List of tested operating systems](#list-of-tested-operating-systems) +- [Installation](#installation) + - [Installation scripts overview](#installation-scripts-overview) + - [Installation modes](#installation-modes) + - [Installation for Ubuntu](#installation-for-ubuntu) + - [Installation for Debian](#installation-for-debian) +- [MyTonCtrl Documentation](#mytonctrl-documentation) +- [Telemetry](#telemetry) +- [MyTonCtrl installer mode](#mytonctrl-installer-mode) + - [Web admin panel](#web-admin-panel) + - [Local copy of toncenter](#local-copy-of-toncenter) +- [Useful links](#useful-links) + + +# What is MyTonCtrl? +MyTonCtrl is a console application that serves as a convenient wrapper for `fift`, `lite-client`, and `validator-engine-console`. It has been specifically developed to streamline wallet, domain, and validator management tasks on the Linux operating system. + +![MyTonCtrl Status](screens/mytonctrl-status.png) + +# Functionality - [x] Show TON network status - [x] Management of local wallets - [x] Create local wallet @@ -45,48 +68,61 @@ This console is a wrapper over `fift`,`lite-client` and `validator-engine-consol - [x] Send validator statistics to https://toncenter.com ## List of tested operating systems -``` -Ubuntu 16.04 LTS (Xenial Xerus) - Error: TON compilation error -Ubuntu 18.04 LTS (Bionic Beaver) - OK -Ubuntu 20.04 LTS (Focal Fossa) - OK -Debian 8 - Error: Unable to locate package libgsl-dev -Debian 9 - Error: TON compilation error -Debian 10 - OK -``` - +| Operating System | Status | +|-------------------------------|----------------------------| +| Ubuntu 16.04 LTS (Xenial Xerus) | Error: TON compilation error | +| Ubuntu 18.04 LTS (Bionic Beaver) | OK | +| Ubuntu 20.04 LTS (Focal Fossa) | OK | +| Ubuntu 22.04 LTS (Jammy Jellyfish) | OK | +| Debian 8 | Error: Unable to locate package libgsl-dev | +| Debian 9 | Error: TON compilation error | +| Debian 10 | OK | + +# Installation ## Installation scripts overview - `toninstaller.sh`: clones `TON` and` mytonctrl` sources to `/usr/src/ton` and`/usr/src/mytonctrl` folders, compiles programs from sources and writes them to `/usr/bin/`. - `mytoninstaller.py`: configures the validator and `mytonctrl`; generates validator connection keys. ## Installation modes -There are two installation modes: `lite` and` full`. They both **compile** and install `TON` components. However the `lite` version does not configure or run the node/validator. +There are two installation modes: `lite` and`full`. They both **compile** and install `TON` components. However the `lite` version does not configure or run the node/validator. ## Installation for Ubuntu 1. Download and execute the `install.sh` script in the desired installation mode. During installation the script prompts you for the superuser password several times. -```sh -wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh -sudo bash install.sh -m -``` + ```sh + wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh + sudo bash install.sh -m + ``` 2. Done. You can try to run the `mytonctrl` console now. -```sh -mytonctrl -``` + ```sh + mytonctrl + ``` ## Installation for Debian 1. Download and execute the `install.sh` script in the desired installation mode. During installation the script prompts you for the superuser password several times. -```sh -wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh -su root -c 'bash install.sh -m ' -``` + ```sh + wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh + su root -c 'bash install.sh -m ' + ``` 2. Done. You can try to run the `mytonctrl` console now. -```sh -mytonctrl -``` + ```sh + mytonctrl + ``` -## Telemetry +# MyTonCtrl Documentation + +This repository contains the following technical documents for MyTonCtrl, categorized by language. Simply click the links below to navigate to the document you're interested in. + +| | FAQ | Import Wallets | Ubuntu Manual | Nominator Pool | +|:-:|:---:|:-------------:|:-------------:|:--------------:| +| **English (EN)** | [Link](./docs/en/FAQ.md) | [Link](./docs/en/import-wallets.md) | [Link](./docs/en/manual-ubuntu.md) | [Link](./docs/en/nominator-pool.md) | +| **Russian (RU)** | [Link](./docs/ru/FAQ.md) | [Link](./docs/ru/import-wallets.md) | [Link](./docs/ru/manual-ubuntu.md) | [Link](./docs/ru/nominator-pool.md) | +| **Traditional Chinese** | [Link](./docs/zh_TW/FAQ.md) | [Link](./docs/zh_TW/import-wallets.md) | [Link](./docs/zh_TW/manual-ubuntu.md) | [Link](./docs/zh_TW/nominator-pool.md) | + + +# Telemetry By default, `mytonctrl` sends validator statistics to the https://toncenter.com server. It is necessary to identify network abnormalities, as well as to quickly give feedback to developers. To disable telemetry during installation, use the `-t` flag: @@ -99,6 +135,8 @@ To disable telemetry after installation, do the following: MyTonCtrl> set sendTelemetry false ``` +# MyTonCtrl installer mode + ## Web admin panel To control the node/validator through the browser, you need to install an additional module: `mytonctrl` -> `installer` -> `enable JR` @@ -111,11 +149,10 @@ git: https://github.com/igroman787/mtc-jsonrpc ## Local copy of toncenter To set up a local https://toncenter.com copy on your server, install an additional module: -`mytonctrl` ->` installer` -> `enable PT` +`mytonctrl` ->`installer` -> `enable PT` Ready. A local copy of toncenter is available at `http://:8000` git: https://github.com/igroman787/pytonv3 -## Useful links -1. https://github.com/ton-blockchain/mytonctrl/blob/master/docs/en/manual-ubuntu.md -2. https://ton.org/docs/ +# Useful links +* https://docs.ton.org/ \ No newline at end of file diff --git a/mypyconsole b/mypyconsole index 3538607e..a8e8969a 160000 --- a/mypyconsole +++ b/mypyconsole @@ -1 +1 @@ -Subproject commit 3538607e412598cace37232c5941673bcdc56ded +Subproject commit a8e8969a6cac6bf96a34655504278d273adad98a diff --git a/mypylib b/mypylib index 8727d55f..1d8fd217 160000 --- a/mypylib +++ b/mypylib @@ -1 +1 @@ -Subproject commit 8727d55f87c56e70ff7d71e293f219136aef5f7c +Subproject commit 1d8fd2172639b7c6d61ded311d2c3a47d60c16b0 diff --git a/mytoncore.py b/mytoncore.py index a4ff4bb8..3a782973 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -8,6 +8,7 @@ import requests import re from mypylib.mypylib import * +from functions.session_stats import read_session_stats local = MyPyClass(__file__) @@ -22,7 +23,8 @@ def __init__(self): def Run(self, cmd, **kwargs): index = kwargs.get("index") - timeout = kwargs.get("timeout", 3) + 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") @@ -44,7 +46,7 @@ def Run(self, cmd, **kwargs): output = process.stdout.decode("utf-8") err = process.stderr.decode("utf-8") if len(err) > 0: - local.AddLog("args: {args}".format(args=args), "error") + local.add_log("args: {args}".format(args=args), "error") raise Exception("LiteClient error: {err}".format(err=err)) return output #end define @@ -59,7 +61,8 @@ def __init__(self): #end define def Run(self, cmd, **kwargs): - timeout = kwargs.get("timeout", 3) + 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] @@ -67,7 +70,7 @@ def Run(self, cmd, **kwargs): output = process.stdout.decode("utf-8") err = process.stderr.decode("utf-8") if len(err) > 0: - local.AddLog("args: {args}".format(args=args), "error") + local.add_log("args: {args}".format(args=args), "error") raise Exception("ValidatorConsole error: {err}".format(err=err)) return output #end define @@ -81,7 +84,8 @@ def __init__(self): #end define def Run(self, args, **kwargs): - timeout = kwargs.get("timeout", 3) + 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 @@ -90,7 +94,7 @@ def Run(self, args, **kwargs): output = process.stdout.decode("utf-8") err = process.stderr.decode("utf-8") if len(err) > 0: - local.AddLog("args: {args}".format(args=args), "error") + local.add_log("args: {args}".format(args=args), "error") raise Exception("Fift error: {err}".format(err=err)) return output #end define @@ -290,15 +294,14 @@ def Init(self): def Refresh(self): if self.dbFile: - local.dbLoad(self.dbFile) - else: - local.dbLoad() + local.load_db(self.dbFile) + #end if if not self.walletsDir: - self.walletsDir = local.buffer.get("myWorkDir") + "wallets/" - self.contractsDir = local.buffer.get("myWorkDir") + "contracts/" - self.poolsDir = local.buffer.get("myWorkDir") + "pools/" - self.tempDir = local.buffer.get("myTempDir") + 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.nodeName = local.db.get("nodeName") if self.nodeName is None: @@ -337,18 +340,19 @@ def Refresh(self): #end define def CheckConfigFile(self, fift, liteClient): - mconfigPath = local.buffer.get("localdbFileName") - backupPath = mconfigPath + ".backup" + mconfig_path = local.buffer.db_path + backup_path = mconfig_path + ".backup" if fift is None or liteClient is None: - local.AddLog("The config file is broken", "warning") - if os.path.isfile(backupPath): - local.AddLog("Restoring the configuration file", "info") - args = ["cp", backupPath, mconfigPath] + local.add_log("The config file is broken", "warning") + print(f"local.db: {local.db}") + if os.path.isfile(backup_path): + local.add_log("Restoring the configuration file", "info") + args = ["cp", backup_path, mconfig_path] subprocess.run(args) self.Refresh() - elif os.path.isfile(backupPath) == False: - local.AddLog("Create backup config file", "info") - args = ["cp", mconfigPath, backupPath] + elif os.path.isfile(backup_path) == False: + local.add_log("Create backup config file", "info") + args = ["cp", mconfig_path, backup_path] subprocess.run(args) #end define @@ -384,7 +388,7 @@ def GetVarFromWorkerOutput(self, text, search): #end define def GetSeqno(self, wallet): - local.AddLog("start GetSeqno function", "debug") + 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: @@ -393,13 +397,13 @@ def GetSeqno(self, wallet): return 0 seqno = self.GetVarFromWorkerOutput(result, "result") seqno = seqno.replace(' ', '') - seqno = Pars(seqno, '[', ']') + seqno = parse(seqno, '[', ']') seqno = int(seqno) return seqno #end define def GetAccount(self, inputAddr): - #local.AddLog("start GetAccount function", "debug") + #local.add_log("start GetAccount function", "debug") workchain, addr = self.ParseInputAddr(inputAddr) account = Account(workchain, addr) cmd = "getaccount {inputAddr}".format(inputAddr=inputAddr) @@ -422,15 +426,15 @@ def GetAccount(self, inputAddr): code = self.GetBody(code) data = self.GetBody(data) codeHash = self.GetCodeHash(code) - status = Pars(state, "account_", '\n') + status = parse(state, "account_", '\n') account.workchain = int(workchain) account.addr = xhex2hex(address) account.addrB64 = self.AddrFull2AddrB64(addrFull) account.addrFull = addrFull account.status = status account.balance = ng2g(value) - account.lt = Pars(result, "lt = ", ' ') - account.hash = Pars(result, "hash = ", '\n') + account.lt = parse(result, "lt = ", ' ') + account.hash = parse(result, "hash = ", '\n') account.codeHash = codeHash return account #end define @@ -444,7 +448,7 @@ def GetCodeHash(self, code): #end define def GetAccountHistory(self, account, limit): - local.AddLog("start GetAccountHistory function", "debug") + local.add_log("start GetAccountHistory function", "debug") addr = f"{account.workchain}:{account.addr}" lt = account.lt transHash = account.hash @@ -467,7 +471,7 @@ def LastTransDump(self, addr, lt, transHash, count=10): for key, item in data.items(): if "transaction #" not in key: continue - block_str = Pars(key, "from block ", ' ') + block_str = parse(key, "from block ", ' ') description = self.GetKeyFromDict(item, "description") type = self.GetVar(description, "trans_") time = self.GetVarFromDict(item, "time") @@ -574,7 +578,7 @@ def GetBody(self, buff): for item in arr: if "x{" not in item: continue - buff = Pars(item, '{', '}') + buff = parse(item, '{', '}') buff = buff.replace('_', '') if len(buff)%2 == 1: buff = "0" + buff @@ -592,7 +596,7 @@ def GetBodyFromDict(self, buff): for item in buff: if "x{" not in item: continue - buff = Pars(item, '{', '}') + buff = parse(item, '{', '}') buff = buff.replace('_', '') if len(buff)%2 == 1: buff = "0" + buff @@ -624,7 +628,7 @@ def GetDomainAddr(self, domainName): result = self.liteClient.Run(cmd) if "not found" in result: raise Exception("GetDomainAddr error: domain \"{domainName}\" not found".format(domainName=domainName)) - resolver = Pars(result, "next resolver", '\n') + resolver = parse(result, "next resolver", '\n') buff = resolver.replace(' ', '') buffList = buff.split('=') fullHexAddr = buffList[0] @@ -633,7 +637,7 @@ def GetDomainAddr(self, domainName): #end define def GetDomainEndTime(self, domainName): - local.AddLog("start GetDomainEndTime function", "debug") + local.add_log("start GetDomainEndTime function", "debug") buff = domainName.split('.') subdomain = buff.pop(0) dnsDomain = ".".join(buff) @@ -641,28 +645,28 @@ def GetDomainEndTime(self, domainName): cmd = "runmethodfull {addr} getexpiration \"{subdomain}\"".format(addr=dnsAddr, subdomain=subdomain) result = self.liteClient.Run(cmd) - result = Pars(result, "result:", '\n') - result = Pars(result, "[", "]") + result = parse(result, "result:", '\n') + result = parse(result, "[", "]") result = result.replace(' ', '') result = int(result) return result #end define def GetDomainAdnlAddr(self, domainName): - local.AddLog("start GetDomainAdnlAddr function", "debug") + local.add_log("start GetDomainAdnlAddr function", "debug") cmd = "dnsresolve {domainName} 1".format(domainName=domainName) result = self.liteClient.Run(cmd) lines = result.split('\n') for line in lines: if "adnl address" in line: - adnlAddr = Pars(line, "=", "\n") + adnlAddr = parse(line, "=", "\n") adnlAddr = adnlAddr.replace(' ', '') adnlAddr = adnlAddr return adnlAddr #end define def GetLocalWallet(self, walletName, version=None, subwallet=None): - #local.AddLog("start GetLocalWallet function", "debug") + local.add_log("start GetLocalWallet function", "debug") if walletName is None: return None walletPath = self.walletsDir + walletName @@ -674,7 +678,7 @@ def GetLocalWallet(self, walletName, version=None, subwallet=None): #end define def GetWalletFromFile(self, filePath, version): - #local.AddLog("start GetWalletFromFile function", "debug") + local.add_log("start GetWalletFromFile function", "debug") # Check input args if (".addr" in filePath): filePath = filePath.replace(".addr", '') @@ -693,7 +697,7 @@ def GetWalletFromFile(self, filePath, version): #end define def GetHighWalletFromFile(self, filePath, subwallet, version): - local.AddLog("start GetHighWalletFromFile function", "debug") + local.add_log("start GetHighWalletFromFile function", "debug") # Check input args if (".addr" in filePath): filePath = filePath.replace(".addr", '') @@ -725,7 +729,7 @@ def AddrFile2Object(self, object): #end define def WalletVersion2Wallet(self, wallet): - #local.AddLog("start WalletVersion2Wallet function", "debug") + local.add_log("start WalletVersion2Wallet function", "debug") if wallet.version is not None: return walletsVersionList = self.GetWalletsVersionList() @@ -734,7 +738,7 @@ def WalletVersion2Wallet(self, wallet): if version is None: version = self.GetWalletVersionFromHash(account.codeHash) if version is None: - local.AddLog("Wallet version not found: " + wallet.addrB64, "warning") + local.add_log("Wallet version not found: " + wallet.addrB64, "warning") return #end if @@ -745,11 +749,11 @@ def WalletVersion2Wallet(self, wallet): def SetWalletVersion(self, addrB64, version): walletsVersionList = self.GetWalletsVersionList() walletsVersionList[addrB64] = version - local.dbSave() + local.save() #end define def GetWalletVersionFromHash(self, inputHash): - #local.AddLog("start GetWalletVersionFromHash function", "debug") + local.add_log("start GetWalletVersionFromHash function", "debug") arr = dict() arr["v1r1"] = "d670136510daff4fee1889b8872c4c1e89872ffa1fe58a23a5f5d99cef8edf32" arr["v1r2"] = "2705a31a7ac162295c8aed0761cc6e031ab65521dd7b4a14631099e02de99e18" @@ -768,8 +772,8 @@ def GetWalletVersionFromHash(self, inputHash): arr["controller_r2"] = "01118b9553151fb9bc81704a4b3e0fc7b899871a527d44435a51574806863e2c" arr["controller_r3"] = "e4d8ce8ff7b4b60c76b135eb8702ce3c86dc133fcee7d19c7aa18f71d9d91438" arr["controller_r4"] = "dec125a4850c4ba24668d84252b04c6ad40abf5c9d413a429b56bfff09ea25d4" - for version, codeHash in arr.items(): - if codeHash == inputHash: + for version, hash in arr.items(): + if hash == inputHash: return version #end for #end define @@ -791,7 +795,7 @@ def GetFullConfigAddr(self): return buff #end if - local.AddLog("start GetFullConfigAddr function", "debug") + 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) @@ -810,7 +814,7 @@ def GetFullElectorAddr(self): #end if # Get data - local.AddLog("start GetFullElectorAddr function", "debug") + 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) @@ -828,7 +832,7 @@ def GetFullMinterAddr(self): return buff #end if - local.AddLog("start GetFullMinterAddr function", "debug") + 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) @@ -846,7 +850,7 @@ def GetFullDnsRootAddr(self): return buff #end if - local.AddLog("start GetFullDnsRootAddr function", "debug") + 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) @@ -864,12 +868,12 @@ def GetActiveElectionId(self, fullElectorAddr): return buff #end if - local.AddLog("start GetActiveElectionId function", "debug") + 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") activeElectionId = activeElectionId.replace(' ', '') - activeElectionId = Pars(activeElectionId, '[', ']') + activeElectionId = parse(activeElectionId, '[', ']') activeElectionId = int(activeElectionId) # Set buffer @@ -878,26 +882,26 @@ def GetActiveElectionId(self, fullElectorAddr): #end define def GetValidatorsElectedFor(self): - local.AddLog("start GetValidatorsElectedFor function", "debug") + local.add_log("start GetValidatorsElectedFor function", "debug") config15 = self.GetConfig15() return config15["validatorsElectedFor"] #end define def GetMinStake(self): - local.AddLog("start GetMinStake function", "debug") + local.add_log("start GetMinStake function", "debug") config17 = self.GetConfig17() return config17["minStake"] #end define def GetRootWorkchainEnabledTime(self): - local.AddLog("start GetRootWorkchainEnabledTime function", "debug") + 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.AddLog("start GetTotalValidators function", "debug") + local.add_log("start GetTotalValidators function", "debug") config34 = self.GetConfig34() result = config34["totalValidators"] return result @@ -920,7 +924,7 @@ def GetInitBlock_new(self): #block = self.GetLastBlock() #cmd = f"gethead {block}" #result = self.liteClient.Run(cmd) - #seqno = Pars(result, "prev_key_block_seqno=", '\n') + #seqno = parse(result, "prev_key_block_seqno=", '\n') statesDir = "/var/ton-work/db/archive/states" os.chdir(statesDir) files = filter(os.path.isfile, os.listdir(statesDir)) @@ -941,7 +945,7 @@ def GetInitBlock(self): block = self.GetLastBlock() cmd = f"gethead {block}" result = self.liteClient.Run(cmd) - seqno = Pars(result, "prev_key_block_seqno=", '\n') + seqno = parse(result, "prev_key_block_seqno=", '\n') data = self.GetBlockHead(-1, 8000000000000000, seqno) return data #end define @@ -959,7 +963,7 @@ def GetBlock(self, workchain, shardchain, seqno): cmd = "byseqno {workchain}:{shardchain} {seqno}" cmd = cmd.format(workchain=workchain, shardchain=shardchain, seqno=seqno) result = self.liteClient.Run(cmd) - block_str = Pars(result, "block header of ", ' ') + block_str = parse(result, "block header of ", ' ') block = Block(block_str) return block #end define @@ -1041,30 +1045,30 @@ def GetValidatorStatus(self): return buff #end if - # local.AddLog("start GetValidatorStatus function", "debug") + # local.add_log("start GetValidatorStatus function", "debug") validatorStatus = dict() try: validatorStatus["isWorking"] = True result = self.validatorConsole.Run("getstats") - validatorStatus["unixtime"] = int(Pars(result, "unixtime", '\n')) - validatorStatus["masterchainblocktime"] = int(Pars(result, "masterchainblocktime", '\n')) - validatorStatus["stateserializermasterchainseqno"] = int(Pars(result, "stateserializermasterchainseqno", '\n')) - validatorStatus["shardclientmasterchainseqno"] = int(Pars(result, "shardclientmasterchainseqno", '\n')) - buff = Pars(result, "masterchainblock", '\n') + validatorStatus["unixtime"] = int(parse(result, "unixtime", '\n')) + validatorStatus["masterchainblocktime"] = int(parse(result, "masterchainblocktime", '\n')) + validatorStatus["stateserializermasterchainseqno"] = int(parse(result, "stateserializermasterchainseqno", '\n')) + validatorStatus["shardclientmasterchainseqno"] = int(parse(result, "shardclientmasterchainseqno", '\n')) + buff = parse(result, "masterchainblock", '\n') validatorStatus["masterchainblock"] = self.GVS_GetItemFromBuff(buff) - buff = Pars(result, "gcmasterchainblock", '\n') + buff = parse(result, "gcmasterchainblock", '\n') validatorStatus["gcmasterchainblock"] = self.GVS_GetItemFromBuff(buff) - buff = Pars(result, "keymasterchainblock", '\n') + buff = parse(result, "keymasterchainblock", '\n') validatorStatus["keymasterchainblock"] = self.GVS_GetItemFromBuff(buff) - buff = Pars(result, "rotatemasterchainblock", '\n') + 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) except Exception as ex: - local.AddLog(f"GetValidatorStatus warning: {ex}", "warning") + local.add_log(f"GetValidatorStatus warning: {ex}", "warning") validatorStatus["isWorking"] = False - validatorStatus["unixtime"] = GetTimestamp() + validatorStatus["unixtime"] = get_timestamp() validatorStatus["masterchainblocktime"] = 0 validatorStatus["outOfSync"] = validatorStatus["unixtime"] - validatorStatus["masterchainblocktime"] @@ -1094,7 +1098,7 @@ def GetConfig(self, configId): #end if text = "start GetConfig function ({})".format(configId) - local.AddLog(text, "debug") + local.add_log(text, "debug") cmd = "getconfig {configId}".format(configId=configId) result = self.liteClient.Run(cmd) start = result.find("ConfigParam") @@ -1133,22 +1137,22 @@ def GetConfig32(self): return buff #end if - local.AddLog("start GetConfig32 function", "debug") + local.add_log("start GetConfig32 function", "debug") config32 = dict() result = self.liteClient.Run("getconfig 32") - config32["totalValidators"] = int(Pars(result, "total:", ' ')) - config32["startWorkTime"] = int(Pars(result, "utime_since:", ' ')) - config32["endWorkTime"] = int(Pars(result, "utime_until:", ' ')) + config32["totalValidators"] = int(parse(result, "total:", ' ')) + config32["startWorkTime"] = int(parse(result, "utime_since:", ' ')) + config32["endWorkTime"] = int(parse(result, "utime_until:", ' ')) lines = result.split('\n') validators = list() for line in lines: if "public_key:" in line: - validatorAdnlAddr = Pars(line, "adnl_addr:x", ')') - pubkey = Pars(line, "pubkey:x", ')') + validatorAdnlAddr = parse(line, "adnl_addr:x", ')') + pubkey = parse(line, "pubkey:x", ')') if config32["totalValidators"] > 1: - validatorWeight = int(Pars(line, "weight:", ' ')) + validatorWeight = int(parse(line, "weight:", ' ')) else: - validatorWeight = int(Pars(line, "weight:", ')')) + validatorWeight = int(parse(line, "weight:", ')')) buff = dict() buff["adnlAddr"] = validatorAdnlAddr buff["pubkey"] = pubkey @@ -1169,23 +1173,23 @@ def GetConfig34(self): return buff #end if - local.AddLog("start GetConfig34 function", "debug") + local.add_log("start GetConfig34 function", "debug") config34 = dict() result = self.liteClient.Run("getconfig 34") - config34["totalValidators"] = int(Pars(result, "total:", ' ')) - config34["startWorkTime"] = int(Pars(result, "utime_since:", ' ')) - config34["endWorkTime"] = int(Pars(result, "utime_until:", ' ')) - config34["totalWeight"] = int(Pars(result, "total_weight:", ' ')) + config34["totalValidators"] = int(parse(result, "total:", ' ')) + config34["startWorkTime"] = int(parse(result, "utime_since:", ' ')) + config34["endWorkTime"] = int(parse(result, "utime_until:", ' ')) + config34["totalWeight"] = int(parse(result, "total_weight:", ' ')) lines = result.split('\n') validators = list() for line in lines: if "public_key:" in line: - validatorAdnlAddr = Pars(line, "adnl_addr:x", ')') - pubkey = Pars(line, "pubkey:x", ')') + validatorAdnlAddr = parse(line, "adnl_addr:x", ')') + pubkey = parse(line, "pubkey:x", ')') if config34["totalValidators"] > 1: - validatorWeight = int(Pars(line, "weight:", ' ')) + validatorWeight = int(parse(line, "weight:", ' ')) else: - validatorWeight = int(Pars(line, "weight:", ')')) + validatorWeight = int(parse(line, "weight:", ')')) buff = dict() buff["adnlAddr"] = validatorAdnlAddr buff["pubkey"] = pubkey @@ -1206,20 +1210,20 @@ def GetConfig36(self): return buff #end if - local.AddLog("start GetConfig36 function", "debug") + local.add_log("start GetConfig36 function", "debug") config36 = dict() try: result = self.liteClient.Run("getconfig 36") - config36["totalValidators"] = int(Pars(result, "total:", ' ')) - config36["startWorkTime"] = int(Pars(result, "utime_since:", ' ')) - config36["endWorkTime"] = int(Pars(result, "utime_until:", ' ')) + config36["totalValidators"] = int(parse(result, "total:", ' ')) + config36["startWorkTime"] = int(parse(result, "utime_since:", ' ')) + config36["endWorkTime"] = int(parse(result, "utime_until:", ' ')) lines = result.split('\n') validators = list() for line in lines: if "public_key:" in line: - validatorAdnlAddr = Pars(line, "adnl_addr:x", ')') - pubkey = Pars(line, "pubkey:x", ')') - validatorWeight = Pars(line, "weight:", ' ') + validatorAdnlAddr = parse(line, "adnl_addr:x", ')') + pubkey = parse(line, "pubkey:x", ')') + validatorWeight = parse(line, "weight:", ' ') buff = dict() buff["adnlAddr"] = validatorAdnlAddr buff["pubkey"] = pubkey @@ -1236,21 +1240,21 @@ def GetConfig36(self): #end define def CreateNewKey(self): - local.AddLog("start CreateNewKey function", "debug") + local.add_log("start CreateNewKey function", "debug") result = self.validatorConsole.Run("newkey") - key = Pars(result, "created new key ", '\n') + key = parse(result, "created new key ", '\n') return key #end define def GetPubKeyBase64(self, key): - local.AddLog("start GetPubKeyBase64 function", "debug") + local.add_log("start GetPubKeyBase64 function", "debug") result = self.validatorConsole.Run("exportpub " + key) - validatorPubkey_b64 = Pars(result, "got public key: ", '\n') + validatorPubkey_b64 = parse(result, "got public key: ", '\n') return validatorPubkey_b64 #end define def GetPubKey(self, key): - local.AddLog("start GetPubKey function", "debug") + local.add_log("start GetPubKey function", "debug") pubkey_b64 = self.GetPubKeyBase64(key) buff = pubkey_b64.encode("utf-8") buff = base64.b64decode(buff) @@ -1261,7 +1265,7 @@ def GetPubKey(self, key): #end define def AddKeyToValidator(self, key, startWorkTime, endWorkTime): - local.AddLog("start AddKeyToValidator function", "debug") + 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) @@ -1271,7 +1275,7 @@ def AddKeyToValidator(self, key, startWorkTime, endWorkTime): #end define def AddKeyToTemp(self, key, endWorkTime): - local.AddLog("start AddKeyToTemp function", "debug") + 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): @@ -1280,7 +1284,7 @@ def AddKeyToTemp(self, key, endWorkTime): #end define def AddAdnlAddrToValidator(self, adnlAddr): - local.AddLog("start AddAdnlAddrToValidator function", "debug") + local.add_log("start AddAdnlAddrToValidator function", "debug") output = False result = self.validatorConsole.Run("addadnl {adnlAddr} 0".format(adnlAddr=adnlAddr)) if ("success" in result): @@ -1294,7 +1298,7 @@ def GetAdnlAddr(self): #end define def AttachAdnlAddrToValidator(self, adnlAddr, key, endWorkTime): - local.AddLog("start AttachAdnlAddrToValidator function", "debug") + 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): @@ -1303,11 +1307,11 @@ def AttachAdnlAddrToValidator(self, adnlAddr, key, endWorkTime): #end define def CreateConfigProposalRequest(self, offerHash, validatorIndex): - local.AddLog("start CreateConfigProposalRequest function", "debug") + 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) - fileName = Pars(result, "Saved to file ", '\n') + fileName = parse(result, "Saved to file ", '\n') resultList = result.split('\n') i = 0 start_index = 0 @@ -1321,11 +1325,11 @@ def CreateConfigProposalRequest(self, offerHash, validatorIndex): #end define def CreateComplaintRequest(self, electionId , complaintHash, validatorIndex): - local.AddLog("start CreateComplaintRequest function", "debug") + 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) - fileName = Pars(result, "Saved to file ", '\n') + fileName = parse(result, "Saved to file ", '\n') resultList = result.split('\n') i = 0 start_index = 0 @@ -1339,20 +1343,20 @@ def CreateComplaintRequest(self, electionId , complaintHash, validatorIndex): #end define def PrepareComplaint(self, electionId, inputFileName): - local.AddLog("start PrepareComplaint function", "debug") + 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) - fileName = Pars(result, "Saved to file ", ')') + fileName = parse(result, "Saved to file ", ')') return fileName #end define def CreateElectionRequest(self, addrB64, startWorkTime, adnlAddr, maxFactor): - local.AddLog("start CreateElectionRequest function", "debug") + local.add_log("start CreateElectionRequest function", "debug") fileName = self.tempDir + self.nodeName + str(startWorkTime) + "_validator-to-sign.bin" args = ["validator-elect-req.fif", addrB64, startWorkTime, maxFactor, adnlAddr, fileName] result = self.fift.Run(args) - fileName = Pars(result, "Saved to file ", '\n') + fileName = parse(result, "Saved to file ", '\n') resultList = result.split('\n') i = 0 start_index = 0 @@ -1366,25 +1370,25 @@ def CreateElectionRequest(self, addrB64, startWorkTime, adnlAddr, maxFactor): #end define def GetValidatorSignature(self, validatorKey, var1): - local.AddLog("start GetValidatorSignature function", "debug") + local.add_log("start GetValidatorSignature function", "debug") cmd = "sign {validatorKey} {var1}".format(validatorKey=validatorKey, var1=var1) result = self.validatorConsole.Run(cmd) - validatorSignature = Pars(result, "got signature ", '\n') + validatorSignature = parse(result, "got signature ", '\n') return validatorSignature #end define def SignElectionRequestWithValidator(self, wallet, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor): - local.AddLog("start SignElectionRequestWithValidator function", "debug") + 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) - pubkey = Pars(result, "validator public key ", '\n') - fileName = Pars(result, "Saved to file ", '\n') + pubkey = parse(result, "validator public key ", '\n') + fileName = parse(result, "Saved to file ", '\n') return pubkey, fileName #end define def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): - local.AddLog("start SignBocWithWallet function", "debug") + local.add_log("start SignBocWithWallet function", "debug") flags = kwargs.get("flags", list()) subwalletDefault = 698983191 + wallet.workchain # 0x29A9A317 + workchain subwallet = kwargs.get("subwallet", subwalletDefault) @@ -1401,7 +1405,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.AddLog(text, "warning") + 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 @@ -1422,12 +1426,12 @@ def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): if flags: args += flags result = self.fift.Run(args) - resultFilePath = Pars(result, "Saved to file ", ")") + resultFilePath = parse(result, "Saved to file ", ")") return resultFilePath #end define def SendFile(self, filePath, wallet=None, **kwargs): - local.AddLog("start SendFile function: " + filePath, "debug") + local.add_log("start SendFile function: " + filePath, "debug") timeout = kwargs.get("timeout", 30) remove = kwargs.get("remove", True) duplicateSendfile = local.db.get("duplicateSendfile", True) @@ -1446,7 +1450,7 @@ def SendFile(self, filePath, wallet=None, **kwargs): #end define def WaitTransaction(self, wallet, timeout=30): - local.AddLog("start WaitTransaction function", "debug") + local.add_log("start WaitTransaction function", "debug") timesleep = 3 steps = timeout // timesleep for i in range(steps): @@ -1458,23 +1462,23 @@ def WaitTransaction(self, wallet, timeout=30): #end define def GetReturnedStake(self, fullElectorAddr, inputAddr): - local.AddLog("start GetReturnedStake function", "debug") + 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) returnedStake = self.GetVarFromWorkerOutput(result, "result") returnedStake = returnedStake.replace(' ', '') - returnedStake = Pars(returnedStake, '[', ']') + returnedStake = parse(returnedStake, '[', ']') returnedStake = ng2g(returnedStake) return returnedStake #end define def ProcessRecoverStake(self): - local.AddLog("start ProcessRecoverStake function", "debug") + local.add_log("start ProcessRecoverStake function", "debug") resultFilePath = self.tempDir + self.nodeName + "recover-query" args = ["recover-stake.fif", resultFilePath] result = self.fift.Run(args) - resultFilePath = Pars(result, "Saved to file ", '\n') + resultFilePath = parse(result, "Saved to file ", '\n') return resultFilePath #end define @@ -1484,7 +1488,6 @@ def GetStake(self, account, args=None): useController = local.db.get("useController") stakePercent = local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() - validators = vconfig.get("validators") config17 = self.GetConfig17() # Check if optional arguments have been passed to us @@ -1498,7 +1501,7 @@ def GetStake(self, account, args=None): # Stake was a number stake = int(desiredStake) else: - local.AddLog("Specified stake must be a percentage or whole number", "error") + 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) @@ -1513,25 +1516,25 @@ def GetStake(self, account, args=None): if stake is None: sp = stakePercent / 100 if sp > 1 or sp < 0: - local.AddLog("Wrong stakePercent value. Using default stake.", "warning") - elif len(validators) == 0: + local.add_log("Wrong stakePercent value. Using default stake.", "warning") + elif len(vconfig.validators) == 0: stake = int(account.balance*sp/2) - elif len(validators) > 0: + elif len(vconfig.validators) > 0: stake = int(account.balance*sp) #end if # 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.AddLog(text, "warning") + 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.AddLog(text, "error") + #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.AddLog(text, "error") + #local.add_log(text, "error") raise Exception(text) #end if @@ -1549,7 +1552,7 @@ def GetMaxFactor(self): #end define def GetValidatorWallet(self, mode="stake"): - #local.AddLog("start GetValidatorWallet function", "debug") + local.add_log("start GetValidatorWallet function", "debug") walletName = local.db.get("validatorWalletName") wallet = self.GetLocalWallet(walletName) if wallet is None: @@ -1563,12 +1566,12 @@ def ElectionEntry(self, args=None): wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 - local.AddLog("start ElectionEntry function", "debug") + local.add_log("start ElectionEntry function", "debug") # Check if validator is not synchronized validatorStatus = self.GetValidatorStatus() validatorOutOfSync = validatorStatus.get("outOfSync") if validatorOutOfSync > 60: - local.AddLog("Validator is not synchronized", "error") + local.add_log("Validator is not synchronized", "error") return #end if @@ -1578,7 +1581,7 @@ def ElectionEntry(self, args=None): # Check if elections started if (startWorkTime == 0): - local.AddLog("Elections have not yet begun", "info") + local.add_log("Elections have not yet begun", "info") return #end if @@ -1594,7 +1597,7 @@ def ElectionEntry(self, args=None): # Check if election entry already completed entries = self.GetElectionEntries() if adnlAddr in entries: - local.AddLog("Elections entry already completed", "info") + local.add_log("Elections entry already completed", "info") return #end if @@ -1630,7 +1633,7 @@ def ElectionEntry(self, args=None): if usePool: var1 = self.CreateElectionRequest(pool.addrB64, startWorkTime, adnlAddr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) - validatorPubkey, resultFilePath = self.SignElectionRequestWithPool(pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) + validatorPubkey, resultFilePath = self.SignElectionRequestWithPoolWithValidator(pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) # Send boc file to TON resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 1.3) @@ -1656,15 +1659,14 @@ 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.AddLog("ElectionEntry completed. Start work time: " + str(startWorkTime)) + local.add_log("ElectionEntry completed. Start work time: " + str(startWorkTime)) #end define def GetValidatorKeyByTime(self, startWorkTime, endWorkTime): - local.AddLog("start GetValidatorKeyByTime function", "debug") + local.add_log("start GetValidatorKeyByTime function", "debug") # Check temp key vconfig = self.GetValidatorConfig() - validators = vconfig.get("validators") - for item in validators: + for item in vconfig.validators: if item.get("election_date") == startWorkTime: validatorKey_b64 = item.get("id") validatorKey = base64.b64decode(validatorKey_b64).hex() @@ -1681,31 +1683,31 @@ def GetValidatorKeyByTime(self, startWorkTime, endWorkTime): def RecoverStake(self): wallet = self.GetValidatorWallet() - local.AddLog("start RecoverStake function", "debug") + local.add_log("start RecoverStake function", "debug") fullElectorAddr = self.GetFullElectorAddr() returnedStake = self.GetReturnedStake(fullElectorAddr, wallet.addrB64) if returnedStake == 0: - local.AddLog("You have nothing on the return stake", "debug") + 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.AddLog("RecoverStake completed") + local.add_log("RecoverStake completed") #end define def PoolRecoverStake(self, poolAddr): wallet = self.GetValidatorWallet() - local.AddLog("start PoolRecoverStake function", "debug") + local.add_log("start PoolRecoverStake function", "debug") resultFilePath = self.PoolProcessRecoverStake() resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, poolAddr, 1.2) self.SendFile(resultFilePath, wallet) - local.AddLog("PoolRecoverStake completed") + local.add_log("PoolRecoverStake completed") #end define def PoolsUpdateValidatorSet(self): - local.AddLog("start PoolsUpdateValidatorSet function", "debug") + local.add_log("start PoolsUpdateValidatorSet function", "debug") wallet = self.GetValidatorWallet() pools = self.GetPools() for pool in pools: @@ -1713,7 +1715,7 @@ def PoolsUpdateValidatorSet(self): #end define def PoolUpdateValidatorSet(self, pool, wallet): - local.AddLog("start PoolUpdateValidatorSet function", "debug") + local.add_log("start PoolUpdateValidatorSet function", "debug") poolAddr = pool.addrB64 poolData = self.GetPoolData(poolAddr) if poolData is None: @@ -1744,32 +1746,32 @@ def PoolUpdateValidatorSet(self, pool, wallet): #end define def PoolProcessUpdateValidatorSet(self, poolAddr, wallet): - local.AddLog("start PoolProcessUpdateValidatorSet function", "debug") + 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] result = self.fift.Run(args) - resultFilePath = Pars(result, "Saved to file ", '\n') + resultFilePath = parse(result, "Saved to file ", '\n') resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, poolAddr, 1.1) self.SendFile(resultFilePath, wallet) - local.AddLog("PoolProcessUpdateValidatorSet completed") + local.add_log("PoolProcessUpdateValidatorSet completed") #end define def PoolWithdrawRequests(self, pool, wallet): - local.AddLog("start PoolWithdrawRequests function", "debug") + local.add_log("start PoolWithdrawRequests function", "debug") resultFilePath = self.PoolProcessWihtdrawRequests() resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 10) self.SendFile(resultFilePath, wallet) - local.AddLog("PoolWithdrawRequests completed") + local.add_log("PoolWithdrawRequests completed") #end define def PoolProcessWihtdrawRequests(self): - local.AddLog("start PoolProcessWihtdrawRequests function", "debug") + 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] result = self.fift.Run(args) - resultFilePath = Pars(result, "Saved to file ", '\n') + resultFilePath = parse(result, "Saved to file ", '\n') return resultFilePath #end define @@ -1785,7 +1787,7 @@ def HasPoolWithdrawRequests(self, pool): #end define def SaveElectionVarsToJsonFile(self, **kwargs): - local.AddLog("start SaveElectionVarsToJsonFile function", "debug") + 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") @@ -1800,12 +1802,12 @@ def SaveElectionVarsToJsonFile(self, **kwargs): #ned define def CreateWallet(self, name, workchain=0, version="v1", **kwargs): - local.AddLog("start CreateWallet function", "debug") + 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.AddLog("CreateWallet error: Wallet already exists: " + name, "warning") + local.add_log("CreateWallet error: Wallet already exists: " + name, "warning") else: if "v1" in version: fiftScript = "new-wallet.fif" @@ -1830,10 +1832,10 @@ def CreateHighWallet(self, name, **kwargs): subwalletDefault = 698983191 + workchain # 0x29A9A317 + workchain subwallet = kwargs.get("subwallet", subwalletDefault) version = kwargs.get("version", "hv1") - local.AddLog("start CreateHighWallet function", "debug") + local.add_log("start CreateHighWallet function", "debug") walletPath = self.walletsDir + name if os.path.isfile(walletPath + ".pk") and os.path.isfile(walletPath + str(subwallet) + ".addr"): - local.AddLog("CreateHighWallet error: Wallet already exists: " + name + str(subwallet), "warning") + local.add_log("CreateHighWallet error: Wallet already exists: " + name + str(subwallet), "warning") else: args = ["new-highload-wallet.fif", workchain, subwallet, walletPath] result = self.fift.Run(args) @@ -1846,12 +1848,12 @@ def CreateHighWallet(self, name, **kwargs): #end define def ActivateWallet(self, wallet): - local.AddLog("start ActivateWallet function", "debug") + 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.AddLog("ActivateWallet warning: account status is active", "warning") + local.add_log("ActivateWallet warning: account status is active", "warning") else: self.SendFile(wallet.bocFilePath, wallet, remove=False) #end define @@ -1887,7 +1889,7 @@ def ExportWallet(self, walletName): #end define def GetWalletsNameList(self): - local.AddLog("start GetWalletsNameList function", "debug") + local.add_log("start GetWalletsNameList function", "debug") walletsNameList = list() for fileName in os.listdir(self.walletsDir): if fileName.endswith(".addr"): @@ -1900,7 +1902,7 @@ def GetWalletsNameList(self): #end define def GetWallets(self): - local.AddLog("start GetWallets function", "debug") + local.add_log("start GetWallets function", "debug") wallets = list() walletsNameList = self.GetWalletsNameList() for walletName in walletsNameList: @@ -1910,7 +1912,7 @@ def GetWallets(self): #end define def GenerateWalletName(self): - local.AddLog("start GenerateWalletName function", "debug") + local.add_log("start GenerateWalletName function", "debug") index = 1 index_str = str(index).rjust(3, '0') walletPrefix = "wallet_" @@ -1932,7 +1934,7 @@ def GenerateWalletName(self): #end define def WalletsCheck(self): - local.AddLog("start WalletsCheck function", "debug") + local.add_log("start WalletsCheck function", "debug") wallets = self.GetWallets() for wallet in wallets: if os.path.isfile(wallet.bocFilePath): @@ -1942,16 +1944,16 @@ def WalletsCheck(self): #end define def GetValidatorConfig(self): - local.AddLog("start GetValidatorConfig function", "debug") + #local.add_log("start GetValidatorConfig function", "debug") result = self.validatorConsole.Run("getconfig") - text = Pars(result, "---------", "--------") + text = parse(result, "---------", "--------") vconfig = json.loads(text) - return vconfig + return Dict(vconfig) #end define def GetOverlaysStats(self): - local.AddLog("start GetOverlaysStats function", "debug") - resultFilePath = local.buffer.get("myTempDir") + "getoverlaysstats.json" + local.add_log("start GetOverlaysStats function", "debug") + resultFilePath = 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}") @@ -1969,13 +1971,13 @@ def GetWalletId(self, wallet): result = self.GetVarFromWorkerOutput(result, "result") if result is None or "error" in result: return subwalletDefault - subwallet = Pars(result, '[', ']') + subwallet = parse(result, '[', ']') subwallet = int(subwallet) return subwallet #end define def MoveCoins(self, wallet, dest, coins, **kwargs): - local.AddLog("start MoveCoins function", "debug") + local.add_log("start MoveCoins function", "debug") flags = kwargs.get("flags", list()) timeout = kwargs.get("timeout", 30) subwallet = kwargs.get("subwallet") @@ -2006,13 +2008,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.AddLog(text, "warning") + 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.get("myTempDir") + wallet.name + "_wallet-query" + resultFilePath = 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] @@ -2025,12 +2027,12 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): if flags: args += flags result = self.fift.Run(args) - savedFilePath = Pars(result, "Saved to file ", ")") + savedFilePath = parse(result, "Saved to file ", ")") self.SendFile(savedFilePath, wallet, timeout=timeout) #end define def MoveCoinsThroughProxy(self, wallet, dest, coins): - local.AddLog("start MoveCoinsThroughProxy function", "debug") + 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) @@ -2043,16 +2045,16 @@ def MoveCoinsThroughProxy(self, wallet, dest, coins): #end define def MoveCoinsFromHW(self, wallet, destList, **kwargs): - local.AddLog("start MoveCoinsFromHW function", "debug") + local.add_log("start MoveCoinsFromHW function", "debug") flags = kwargs.get("flags") timeout = kwargs.get("timeout", 30) if len(destList) == 0: - local.AddLog("MoveCoinsFromHW warning: destList is empty, break function", "warning") + local.add_log("MoveCoinsFromHW warning: destList is empty, break function", "warning") return #end if - orderFilePath = local.buffer.get("myTempDir") + wallet.name + "_order.txt" + orderFilePath = 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)) @@ -2066,23 +2068,22 @@ def MoveCoinsFromHW(self, wallet, destList, **kwargs): elif "v2" in wallet.version: fiftScript = "highload-wallet-v2.fif" seqno = self.GetSeqno(wallet) - resultFilePath = local.buffer.get("myTempDir") + wallet.name + "_wallet-query" + resultFilePath = local.buffer.my_temp_dir + wallet.name + "_wallet-query" args = [fiftScript, wallet.path, wallet.subwallet, seqno, orderFilePath, resultFilePath] if flags: args += flags result = self.fift.Run(args) - savedFilePath = Pars(result, "Saved to file ", ")") + savedFilePath = parse(result, "Saved to file ", ")") self.SendFile(savedFilePath, wallet, timeout=timeout) #end define def GetValidatorKey(self): vconfig = self.GetValidatorConfig() - validators = vconfig["validators"] - for validator in validators: + for validator in vconfig.validators: validatorId = validator["id"] key_bytes = base64.b64decode(validatorId) validatorKey = key_bytes.hex().upper() - timestamp = GetTimestamp() + timestamp = get_timestamp() if timestamp > validator["election_date"]: return validatorKey raise Exception("GetValidatorKey error: validator key not found. Are you sure you are a validator?") @@ -2116,7 +2117,7 @@ def GetElectionEntries(self, past=False): #end if # Get raw data - local.AddLog("start GetElectionEntries function", "debug") + 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) @@ -2157,7 +2158,7 @@ def GetElectionEntries(self, past=False): #end define def GetSaveElections(self): - timestamp = GetTimestamp() + timestamp = get_timestamp() saveElections = local.db.get("saveElections") if saveElections is None: saveElections = dict() @@ -2178,7 +2179,7 @@ def GetSaveElectionEntries(self, electionId): #end define def GetOffers(self): - local.AddLog("start GetOffers function", "debug") + local.add_log("start GetOffers function", "debug") fullConfigAddr = self.GetFullConfigAddr() # Get raw data cmd = "runmethodfull {fullConfigAddr} list_proposals".format(fullConfigAddr=fullConfigAddr) @@ -2230,7 +2231,7 @@ def GetOffers(self): #end define def GetOfferDiff(self, offerHash): - local.AddLog("start GetOfferDiff function", "debug") + local.add_log("start GetOfferDiff function", "debug") offer = self.GetOffer(offerHash) configId = offer["config"]["id"] configValue = offer["config"]["value"] @@ -2327,7 +2328,7 @@ def GetComplaints(self, electionId=None, past=False): #end if # Get raw data - local.AddLog("start GetComplaints function", "debug") + 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) @@ -2394,7 +2395,7 @@ def GetComplaints(self, electionId=None, past=False): #end define def GetSaveComplaints(self): - timestamp = GetTimestamp() + timestamp = get_timestamp() saveComplaints = local.db.get("saveComplaints") if type(saveComplaints) is not dict: saveComplaints = dict() @@ -2418,7 +2419,7 @@ def GetAdnlFromPubkey(self, inputPubkey): #end define def GetComplaintsNumber(self): - local.AddLog("start GetComplaintsNumber function", "debug") + local.add_log("start GetComplaintsNumber function", "debug") result = dict() complaints = self.GetComplaints() votedComplaints = self.GetVotedComplaints() @@ -2436,7 +2437,7 @@ def GetComplaintsNumber(self): #end define def GetComplaint(self, electionId, complaintHash): - local.AddLog("start GetComplaint function", "debug") + local.add_log("start GetComplaint function", "debug") complaints = self.GetComplaints(electionId) for key, item in complaints.items(): if complaintHash == item.get("hash"): @@ -2445,25 +2446,25 @@ def GetComplaint(self, electionId, complaintHash): #end define def SignProposalVoteRequestWithValidator(self, offerHash, validatorIndex, validatorPubkey_b64, validatorSignature): - local.AddLog("start SignProposalVoteRequestWithValidator function", "debug") + 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) - fileName = Pars(result, "Saved to file ", '\n') + fileName = parse(result, "Saved to file ", '\n') return fileName #end define def SignComplaintVoteRequestWithValidator(self, complaintHash, electionId, validatorIndex, validatorPubkey_b64, validatorSignature): - local.AddLog("start SignComplaintRequestWithValidator function", "debug") + 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) - fileName = Pars(result, "Saved to file ", '\n') + fileName = parse(result, "Saved to file ", '\n') return fileName #end define def VoteOffer(self, offerHash): - local.AddLog("start VoteOffer function", "debug") + local.add_log("start VoteOffer function", "debug") fullConfigAddr = self.GetFullConfigAddr() wallet = self.GetValidatorWallet(mode="vote") validatorKey = self.GetValidatorKey() @@ -2471,7 +2472,7 @@ def VoteOffer(self, offerHash): validatorIndex = self.GetValidatorIndex() offer = self.GetOffer(offerHash) if validatorIndex in offer.get("votedValidators"): - local.AddLog("Proposal already has been voted", "debug") + local.add_log("Proposal already has been voted", "debug") return var1 = self.CreateConfigProposalRequest(offerHash, validatorIndex) validatorSignature = self.GetValidatorSignature(validatorKey, var1) @@ -2482,7 +2483,7 @@ def VoteOffer(self, offerHash): #end define def VoteComplaint(self, electionId, complaintHash): - local.AddLog("start VoteComplaint function", "debug") + local.add_log("start VoteComplaint function", "debug") complaintHash = int(complaintHash) fullElectorAddr = self.GetFullElectorAddr() wallet = self.GetValidatorWallet(mode="vote") @@ -2493,7 +2494,7 @@ def VoteComplaint(self, electionId, complaintHash): votedValidators = complaint.get("votedValidators") pubkey = complaint.get("pubkey") if validatorIndex in votedValidators: - local.AddLog("Complaint already has been voted", "info") + local.add_log("Complaint already has been voted", "info") return var1 = self.CreateComplaintRequest(electionId, complaintHash, validatorIndex) validatorSignature = self.GetValidatorSignature(validatorKey, var1) @@ -2504,7 +2505,7 @@ def VoteComplaint(self, electionId, complaintHash): #end define def SaveComplaints(self, electionId): - local.AddLog("start SaveComplaints function", "debug") + 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) @@ -2524,7 +2525,7 @@ def SaveComplaints(self, electionId): #end define def CheckComplaint(self, filePath): - local.AddLog("start CheckComplaint function", "debug") + local.add_log("start CheckComplaint function", "debug") cmd = "loadproofcheck {filePath}".format(filePath=filePath) result = self.liteClient.Run(cmd, timeout=30) lines = result.split('\n') @@ -2560,7 +2561,7 @@ def GetValidatorsLoad(self, start, end, saveCompFiles=False): #end if text = "start GetValidatorsLoad function ({}, {})".format(start, end) - local.AddLog(text, "debug") + local.add_log(text, "debug") if saveCompFiles is True: filePrefix = self.tempDir + f"checkload_{start}_{end}" else: @@ -2642,7 +2643,7 @@ def GetValidatorsList(self, past=False): return buff #end if - timestamp = GetTimestamp() + timestamp = get_timestamp() end = timestamp - 60 start = end - 2000 config = self.GetConfig34() @@ -2673,16 +2674,14 @@ def GetValidatorsList(self, past=False): #end define def CheckValidators(self, start, end): - local.AddLog("start CheckValidators function", "debug") + local.add_log("start CheckValidators function", "debug") electionId = start complaints = self.GetComplaints(electionId) data = self.GetValidatorsLoad(start, end, saveCompFiles=True) fullElectorAddr = self.GetFullElectorAddr() wallet = self.GetValidatorWallet(mode="vote") - # Check wallet and balance - if wallet is None: - raise Exception("Validator wallet not fond") + # Check balance account = self.GetAccount(wallet.addrB64) if account.balance < 300: raise Exception("Validator wallet balance must be greater than 300") @@ -2700,11 +2699,11 @@ def CheckValidators(self, start, end): fileName = self.PrepareComplaint(electionId, fileName) fileName = self.SignBocWithWallet(wallet, fileName, fullElectorAddr, 300) self.SendFile(fileName, wallet) - local.AddLog("var1: {}, var2: {}, pubkey: {}, election_id: {}".format(var1, var2, pubkey, electionId), "debug") + local.add_log("var1: {}, var2: {}, pubkey: {}, election_id: {}".format(var1, var2, pubkey, electionId), "debug") #end define def GetOffer(self, offerHash): - local.AddLog("start GetOffer function", "debug") + local.add_log("start GetOffer function", "debug") offers = self.GetOffers() for offer in offers: if offerHash == offer.get("hash"): @@ -2713,7 +2712,7 @@ def GetOffer(self, offerHash): #end define def GetOffersNumber(self): - local.AddLog("start GetOffersNumber function", "debug") + local.add_log("start GetOffersNumber function", "debug") result = dict() offers = self.GetOffers() saveOffers = self.GetSaveOffers() @@ -2739,12 +2738,12 @@ def GetValidatorIndex(self, adnlAddr=None): if adnlAddr == searchAdnlAddr: return index index += 1 - local.AddLog("GetValidatorIndex warning: index not found.", "warning") + local.add_log("GetValidatorIndex warning: index not found.", "warning") return -1 #end define def GetValidatorEfficiency(self, adnlAddr=None): - local.AddLog("start GetValidatorEfficiency function", "debug") + local.add_log("start GetValidatorEfficiency function", "debug") validators = self.GetValidatorsList() if adnlAddr is None: adnlAddr = self.GetAdnlAddr() @@ -2753,7 +2752,27 @@ def GetValidatorEfficiency(self, adnlAddr=None): if adnlAddr == searchAdnlAddr: efficiency = validator.get("efficiency") return efficiency - local.AddLog("GetValidatorEfficiency warning: efficiency not found.", "warning") + local.add_log("GetValidatorEfficiency warning: efficiency not found.", "warning") + #end define + + def GetValidatorEfficiency2(self): + config34 = self.GetConfig34() + validator_uptime = get_service_uptime("validator") + current_round_time = int(time.time()) - config34.get("startWorkTime") + data1 = read_session_stats(600) + data2 = read_session_stats(current_round_time) + data3 = read_session_stats(validator_uptime) + + efficiency1 = 0 + efficiency2 = 0 + efficiency3 = 0 + if data1.my_need_blocks > 0: + efficiency1 = round(data1.my_blocks/data1.my_need_blocks*100, 2) + if data2.my_need_blocks > 0: + efficiency2 = round(data2.my_blocks/data2.my_need_blocks*100, 2) + if data3.my_need_blocks > 0: + efficiency3 = round(data3.my_blocks/data3.my_need_blocks*100, 2) + return [efficiency1, efficiency2, efficiency3] #end define def GetDbUsage(self): @@ -2763,7 +2782,7 @@ def GetDbUsage(self): #end define def GetDbSize(self, exceptions="log"): - local.AddLog("start GetDbSize function", "debug") + local.add_log("start GetDbSize function", "debug") exceptions = exceptions.split() totalSize = 0 path = "/var/ton-work/" @@ -2780,7 +2799,7 @@ def GetDbSize(self, exceptions="log"): #end define def Result2List(self, text): - buff = Pars(text, "result:", "\n") + buff = parse(text, "result:", "\n") if buff is None or "error" in buff: return buff = buff.replace(')', ']') @@ -2914,8 +2933,18 @@ def GetItemFromDict(self, data, search): return None #end define + def GetDomainFromAuction(self, walletName, addr): + wallet = self.GetLocalWallet(walletName) + bocPath = 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.AddLog("start NewDomain function", "debug") + local.add_log("start NewDomain function", "debug") domainName = domain["name"] buff = domainName.split('.') subdomain = buff.pop(0) @@ -2934,7 +2963,7 @@ def NewDomain(self, domain): fileName = self.tempDir + "dns-msg-body.boc" args = ["auto-dns.fif", dnsAddr, "add", subdomain, expireInSec, "owner", wallet.addrB64, "cat", catId, "adnl", domain["adnlAddr"], "-o", fileName] result = self.fift.Run(args) - resultFilePath = Pars(result, "Saved to file ", ')') + resultFilePath = parse(result, "Saved to file ", ')') resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, dnsAddr, 1.7) self.SendFile(resultFilePath, wallet) self.AddDomain(domain) @@ -2945,7 +2974,7 @@ def AddDomain(self, domain): local.db["domains"] = list() #end if local.db["domains"].append(domain) - local.dbSave() + local.save() #end define def GetDomains(self): @@ -2969,7 +2998,7 @@ def DeleteDomain(self, domainName): for domain in domains: if (domainName == domain.get("name")): domains.remove(domain) - local.dbSave() + local.save() return raise Exception("DeleteDomain error: Domain not found") #end define @@ -2985,7 +3014,7 @@ def GetAutoTransferRules(self): def AddAutoTransferRule(self, rule): autoTransferRules = self.GetAutoTransferRules() autoTransferRules.append(rule) - local.dbSave() + local.save() #end define def AddBookmark(self, bookmark): @@ -2993,7 +3022,7 @@ def AddBookmark(self, bookmark): local.db["bookmarks"] = list() #end if local.db["bookmarks"].append(bookmark) - local.dbSave() + local.save() #end define def GetBookmarks(self): @@ -3022,7 +3051,7 @@ def DeleteBookmark(self, name, type): bookmarkName = bookmark.get("name") if (type == bookmarkType and name == bookmarkName): bookmarks.remove(bookmark) - local.dbSave() + local.save() return raise Exception("DeleteBookmark error: Bookmark not found") #end define @@ -3042,7 +3071,7 @@ def WriteBookmarkData(self, bookmark): if endTime == 0: data = "free" else: - data = Timestamp2Datetime(endTime, "%d.%m.%Y") + data = timestamp2datetime(endTime, "%d.%m.%Y") else: data = "null" bookmark["data"] = data @@ -3063,7 +3092,7 @@ def AddSaveOffer(self, offer): saveOffers = self.GetSaveOffers() if offerHash not in saveOffers: saveOffers[offerHash] = offerPseudohash - local.dbSave() + local.save() #end define def GetVotedComplaints(self): @@ -3080,7 +3109,7 @@ def AddVotedComplaints(self, complaint): votedComplaints = self.GetVotedComplaints() if pseudohash not in votedComplaints: votedComplaints[pseudohash] = complaint - local.dbSave() + local.save() #end define def GetDestinationAddr(self, destination): @@ -3148,7 +3177,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.AddLog(text, "warning") + local.add_log(text, "warning") #end if # get wc and addr @@ -3231,7 +3260,7 @@ def GetStatistics(self, name, statistics=None): #end define def GetSettings(self, name): - local.dbLoad() + #local.load_db() result = local.db.get(name) return result #end define @@ -3241,7 +3270,7 @@ def SetSettings(self, name, data): data = json.loads(data) except: pass local.db[name] = data - local.dbSave() + local.save() #end define def Tlb2Json(self, text): @@ -3315,7 +3344,7 @@ def Tlb2Json(self, text): #end define def SignShardOverlayCert(self, adnl, pubkey): - local.AddLog("start SignShardOverlayCert function", "debug") + 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) @@ -3337,7 +3366,7 @@ def SignShardOverlayCert(self, adnl, pubkey): #end define def ImportShardOverlayCert(self): - local.AddLog("start ImportShardOverlayCert function", "debug") + local.add_log("start ImportShardOverlayCert function", "debug") adnlAddr = self.GetAdnlAddr() pubkey = self.GetPubKey(adnlAddr) adnl = pubkey # adnl = adnlAddr @@ -3362,7 +3391,7 @@ def ImportShardOverlayCert(self): # Check certificate if cert is None: - local.AddLog("ImportShardOverlayCert warning: certificate not found", "warning") + local.add_log("ImportShardOverlayCert warning: certificate not found", "warning") return #end if @@ -3374,7 +3403,7 @@ def ImportShardOverlayCert(self): #end define def ImportCertificate(self, pubkey, fileName): - local.AddLog("start ImportCertificate function", "debug") + 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) @@ -3390,7 +3419,7 @@ def GetValidatorsWalletsList(self): #end define def DownloadContract(self, url, branch=None): - local.AddLog("start DownloadContract function", "debug") + local.add_log("start DownloadContract function", "debug") buff = url.split('/') gitPath = self.contractsDir + buff[-1] + '/' @@ -3422,7 +3451,7 @@ def DownloadContract(self, url, branch=None): #end define def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake): - local.AddLog("start CreatePool function", "debug") + local.add_log("start CreatePool function", "debug") validatorRewardShare = int(validatorRewardSharePercent * 100) contractPath = self.contractsDir + "nominator-pool/" if not os.path.isdir(contractPath): @@ -3431,7 +3460,7 @@ def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, filePath = self.poolsDir + poolName if os.path.isfile(filePath + ".addr"): - local.AddLog("CreatePool warning: Pool already exists: " + filePath, "warning") + local.add_log("CreatePool warning: Pool already exists: " + filePath, "warning") return #end if @@ -3453,7 +3482,7 @@ def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, #end define def ActivatePool(self, pool, ex=True): - local.AddLog("start ActivatePool function", "debug") + local.add_log("start ActivatePool function", "debug") for i in range(10): time.sleep(3) account = self.GetAccount(pool.addrB64) @@ -3466,7 +3495,7 @@ def ActivatePool(self, pool, ex=True): def DepositToPool(self, walletName, poolAddr, amount): wallet = self.GetLocalWallet(walletName) - bocPath = local.buffer.get("myTempDir") + wallet.name + "validator-deposit-query.boc" + bocPath = 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) @@ -3474,18 +3503,18 @@ def DepositToPool(self, walletName, poolAddr, amount): self.SendFile(resultFilePath, wallet) #end define - def WithdrawFromPool(self, walletName, poolAddr, amount): + def WithdrawFromPool(self, poolAddr, amount): poolData = self.GetPoolData(poolAddr) if poolData["state"] == 0: - self.WithdrawFromPoolProcess(walletName, poolAddr, amount) + self.WithdrawFromPoolProcess(poolAddr, amount) else: - self.PendWithdrawFromPool(walletName, poolAddr, amount) + self.PendWithdrawFromPool(poolAddr, amount) #end define - def WithdrawFromPoolProcess(self, walletName, poolAddr, amount): - local.AddLog("start WithdrawFromPoolProcess function", "debug") - wallet = self.GetLocalWallet(walletName) - bocPath = local.buffer.get("myTempDir") + wallet.name + "validator-withdraw-query.boc" + 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" fiftScript = self.contractsDir + "nominator-pool/func/validator-withdraw.fif" args = [fiftScript, amount, bocPath] result = self.fift.Run(args) @@ -3493,16 +3522,16 @@ def WithdrawFromPoolProcess(self, walletName, poolAddr, amount): self.SendFile(resultFilePath, wallet) #end define - def PendWithdrawFromPool(self, walletName, poolAddr, amount): - local.AddLog("start PendWithdrawFromPool function", "debug") + def PendWithdrawFromPool(self, poolAddr, amount): + local.add_log("start PendWithdrawFromPool function", "debug") pendingWithdraws = self.GetPendingWithdraws() - pendingWithdraws[poolAddr] = (walletName, amount) - local.dbSave() + pendingWithdraws[poolAddr] = amount + local.save() #end define def HandlePendingWithdraw(self, pendingWithdraws, poolAddr): - walletName, amount = pendingWithdraws.get(poolAddr) - self.WithdrawFromPoolProcess(walletName, poolAddr, amount) + amount = pendingWithdraws.get(poolAddr) + self.WithdrawFromPoolProcess(poolAddr, amount) pendingWithdraws.pop(poolAddr) #end define @@ -3515,29 +3544,29 @@ def GetPendingWithdraws(self): return pendingWithdraws #end define - def SignElectionRequestWithPool(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): - local.AddLog("start SignElectionRequestWithPool function", "debug") + def SignElectionRequestWithPoolWithValidator(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): + 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] result = self.fift.Run(args) - pubkey = Pars(result, "validator public key ", '\n') - fileName = Pars(result, "Saved to file ", '\n') + pubkey = parse(result, "validator public key ", '\n') + fileName = parse(result, "Saved to file ", '\n') return pubkey, fileName #end define def PoolProcessRecoverStake(self): - local.AddLog("start PoolProcessRecoverStake function", "debug") + 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] result = self.fift.Run(args) - resultFilePath = Pars(result, "Saved to file ", '\n') + resultFilePath = parse(result, "Saved to file ", '\n') return resultFilePath #end define def GetLocalPool(self, poolName): - local.AddLog("start GetLocalPool function", "debug") + local.add_log("start GetLocalPool function", "debug") if poolName is None: return None filePath = self.poolsDir + poolName @@ -3553,7 +3582,7 @@ def GetLocalPool(self, poolName): #end define def GetPoolsNameList(self): - local.AddLog("start GetPoolsNameList function", "debug") + local.add_log("start GetPoolsNameList function", "debug") poolsNameList = list() for fileName in os.listdir(self.poolsDir): if fileName.endswith(".addr"): @@ -3564,7 +3593,7 @@ def GetPoolsNameList(self): #end define def GetPools(self): - local.AddLog("start GetPools function", "debug") + local.add_log("start GetPools function", "debug") pools = list() poolsNameList = self.GetPoolsNameList() for poolName in poolsNameList: @@ -3589,7 +3618,7 @@ def GetPoolLastSentStakeTime(self, addrB64): #end define def IsPoolReadyToStake(self, addrB64): - now = GetTimestamp() + now = get_timestamp() config15 = self.GetConfig15() lastSentStakeTime = self.GetPoolLastSentStakeTime(addrB64) stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] @@ -3605,7 +3634,7 @@ def IsPoolReadyToVote(self, addrB64): #end define def GetPoolData(self, addrB64): - local.AddLog("start GetPoolData function", "debug") + local.add_log("start GetPoolData function", "debug") cmd = f"runmethodfull {addrB64} get_pool_data" result = self.liteClient.Run(cmd) data = self.Result2List(result) @@ -4034,7 +4063,7 @@ def GetNetworkName(self): #end define def GetFunctionBuffer(self, name, timeout=10): - timestamp = GetTimestamp() + timestamp = get_timestamp() buff = local.buffer.get(name) if buff is None: return @@ -4048,7 +4077,7 @@ def GetFunctionBuffer(self, name, timeout=10): def SetFunctionBuffer(self, name, data): buff = dict() - buff["time"] = GetTimestamp() + buff["time"] = get_timestamp() buff["data"] = data local.buffer[name] = buff #end define @@ -4093,209 +4122,6 @@ def IsHash(self, inputHash): #end define #end class -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 - def ng2g(ng): if ng is None: return @@ -4310,18 +4136,19 @@ def Init(): Event(eventName) #end if - local.Run() + local.run() # statistics - local.buffer["transData"] = dict() - local.buffer["network"] = [None]*15*6 - local.buffer["diskio"] = [None]*15*6 + 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 + local.buffer.masterBlocksList = list() + local.buffer.prevShardsBlock = dict() + local.buffer.blocksNum = 0 + local.buffer.transNum = 0 #end define def Event(eventName): @@ -4329,11 +4156,11 @@ def Event(eventName): EnableVcEvent() elif eventName == "validator down": ValidatorDownEvent() - local.Exit() + local.exit() #end define def EnableVcEvent(): - local.AddLog("start EnableVcEvent function", "debug") + local.add_log("start EnableVcEvent function", "debug") # Создать новый кошелек для валидатора ton = MyTonCore() wallet = ton.CreateWallet("validator_wallet_001", -1) @@ -4345,12 +4172,12 @@ def EnableVcEvent(): local.db["adnlAddr"] = adnlAddr # Сохранить - local.dbSave() + local.save() #end define def ValidatorDownEvent(): - local.AddLog("start ValidatorDownEvent function", "debug") - local.AddLog("Validator is down", "error") + local.add_log("start ValidatorDownEvent function", "debug") + local.add_log("Validator is down", "error") #end define def Elections(ton): @@ -4369,17 +4196,17 @@ def Elections(ton): ton.ElectionEntry() #end define -def Statistics(scanner): +def Statistics(): ReadNetworkData() SaveNetworkStatistics() - ReadTransData(scanner) + #ReadTransData(scanner) SaveTransStatistics() ReadDiskData() SaveDiskStatistics() #end define def ReadDiskData(): - timestamp = GetTimestamp() + timestamp = get_timestamp() disks = GetDisksList() buff = psutil.disk_io_counters(perdisk=True) data = dict() @@ -4393,12 +4220,12 @@ def ReadDiskData(): data[name]["writeCount"] = buff[name].write_count #end for - local.buffer["diskio"].pop(0) - local.buffer["diskio"].append(data) + local.buffer.diskio.pop(0) + local.buffer.diskio.append(data) #end define def SaveDiskStatistics(): - data = local.buffer["diskio"] + data = local.buffer.diskio data = data[::-1] zerodata = data[0] buff1 = data[1*6-1] @@ -4468,24 +4295,23 @@ def GetDisksList(): #end define def ReadNetworkData(): - timestamp = GetTimestamp() - interfaceName = GetInternetInterfaceName() + timestamp = get_timestamp() + interfaceName = get_internet_interface_name() buff = psutil.net_io_counters(pernic=True) buff = buff[interfaceName] data = dict() - 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) + local.buffer.network.pop(0) + local.buffer.network.append(data) #end define def SaveNetworkStatistics(): - data = local.buffer["network"] + data = local.buffer.network data = data[::-1] zerodata = data[0] buff1 = data[1*6-1] @@ -4530,7 +4356,7 @@ def CalculateNetworkStatistics(zerodata, data): #end define def ReadTransData(scanner): - transData = local.buffer.get("transData") + transData = local.buffer.transData SetToTimeData(transData, scanner.transNum) ShortTimeData(transData) #end define @@ -4585,13 +4411,13 @@ def GetItemFromTimeData(data, timeneed): def GetTps(timediff): - data = local.buffer["transData"] + data = local.buffer.transData tps = GetDataPerSecond(data, timediff) return tps #end define def GetBps(timediff): - data = local.buffer["blocksData"] + data = local.buffer.blocksData bps = GetDataPerSecond(data, timediff) return bps #end define @@ -4646,7 +4472,9 @@ def GetSwapInfo(): #end define def GetValidatorProcessInfo(): - pid = GetServicePid("validator") + pid = get_service_pid("validator") + if pid == None or pid == 0: + return p = psutil.Process(pid) mem = p.memory_info() result = dict() @@ -4675,7 +4503,7 @@ def Telemetry(ton): data["adnlAddr"] = ton.GetAdnlAddr() data["validatorStatus"] = ton.GetValidatorStatus() data["cpuNumber"] = psutil.cpu_count() - data["cpuLoad"] = GetLoadAvg() + data["cpuLoad"] = get_load_avg() data["netLoad"] = ton.GetStatistics("netLoadAvg") data["tps"] = ton.GetStatistics("tpsAvg") data["disksLoad"] = ton.GetStatistics("disksLoadAvg") @@ -4687,16 +4515,20 @@ def Telemetry(ton): data["swap"] = GetSwapInfo() data["uname"] = GetUname() data["vprocess"] = GetValidatorProcessInfo() - elections = local.TryFunction(ton.GetElectionEntries) - complaints = local.TryFunction(ton.GetComplaints) + elections = local.try_function(ton.GetElectionEntries) + complaints = local.try_function(ton.GetComplaints) # Get git hashes gitHashes = dict() - gitHashes["mytonctrl"] = GetGitHash("/usr/src/mytonctrl") + 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) @@ -4704,7 +4536,7 @@ def Telemetry(ton): resp = requests.post(liteUrl, data=output, timeout=3) #end define -def GetBinGitHash(path): +def GetBinGitHash(path, short=False): if not os.path.isfile(path): return args = [path, "--version"] @@ -4715,6 +4547,8 @@ def GetBinGitHash(path): buff = output.split(' ') start = buff.index("Commit:") + 1 result = buff[start].replace(',', '') + if short is True: + result = result[:7] return result #end define @@ -4761,15 +4595,15 @@ def Slashing(ton): #end if # Creating complaints - slashTime = local.buffer.get("slashTime") + slash_time = local.buffer.slash_time config32 = ton.GetConfig32() start = config32.get("startWorkTime") end = config32.get("endWorkTime") - local.AddLog("slashTime {}, start {}, end {}".format(slashTime, start, end), "debug") - if slashTime != start: + 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["slashTime"] = start + local.buffer.slash_time = start #end define def ScanLiteServers(ton): @@ -4795,22 +4629,20 @@ def ScanLiteServers(ton): #end define def General(): - local.AddLog("start General function", "debug") + local.add_log("start General function", "debug") ton = MyTonCore() - scanner = TonBlocksScanner(ton, local=local) - #scanner.Run() # Запустить потоки - local.StartCycle(Elections, sec=600, args=(ton, )) - local.StartCycle(Statistics, sec=10, args=(scanner,)) - local.StartCycle(Offers, sec=600, args=(ton, )) - local.StartCycle(Complaints, sec=600, args=(ton, )) - local.StartCycle(Slashing, sec=600, args=(ton, )) - local.StartCycle(Domains, sec=600, args=(ton, )) - local.StartCycle(Telemetry, sec=60, args=(ton, )) - local.StartCycle(OverlayTelemetry, sec=7200, args=(ton, )) - local.StartCycle(ScanLiteServers, sec=60, args=(ton,)) - Sleep() + 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): diff --git a/mytonctrl.py b/mytonctrl.py index 33cb5596..36267433 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -12,76 +12,77 @@ def Init(argv): # Load translate table - local.InitTranslator(local.buffer.get("myDir") + "translate.json") + local.init_translator(local.buffer.my_dir + "translate.json") # 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("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.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.AddItem("create_controllers", CreateControllers, local.Translate("_")) - console.AddItem("update_controllers", CreateControllers, local.Translate("_")) - console.AddItem("controllers_list", PrintControllersList, local.Translate("_")) - console.AddItem("get_controller_data", GetControllerData, local.Translate("_")) - console.AddItem("deposit_to_controller", DepositToController, local.Translate("_")) - console.AddItem("withdraw_from_controller", WithdrawFromController, local.Translate("_")) - console.AddItem("calculate_annual_controller_percentage", CalculateAnnualControllerPercentage, local.Translate("_")) - console.AddItem("controller_update_validator_set", ControllerUpdateValidatorSet, local.Translate("_")) - console.AddItem("stop_controller", StopController, local.Translate("_")) - console.AddItem("stop_and_withdraw_controller", StopAndWithdrawController, local.Translate("_")) - console.AddItem("add_controller", AddController, local.Translate("_")) - console.AddItem("check_liquid_pool", CheckLiquidPool, local.Translate("_")) + console.AddItem("create_controllers", CreateControllers, local.translate("_")) + console.AddItem("update_controllers", CreateControllers, local.translate("_")) + console.AddItem("controllers_list", PrintControllersList, local.translate("_")) + console.AddItem("get_controller_data", GetControllerData, local.translate("_")) + console.AddItem("deposit_to_controller", DepositToController, local.translate("_")) + console.AddItem("withdraw_from_controller", WithdrawFromController, local.translate("_")) + console.AddItem("calculate_annual_controller_percentage", CalculateAnnualControllerPercentage, local.translate("_")) + console.AddItem("controller_update_validator_set", ControllerUpdateValidatorSet, local.translate("_")) + console.AddItem("stop_controller", StopController, local.translate("_")) + console.AddItem("stop_and_withdraw_controller", StopAndWithdrawController, local.translate("_")) + console.AddItem("add_controller", AddController, local.translate("_")) + console.AddItem("check_liquid_pool", CheckLiquidPool, local.translate("_")) # Process input parameters @@ -109,13 +110,14 @@ def Init(argv): ton.walletsDir = wallets #end for - local.db["config"]["logLevel"] = "debug" - local.db["config"]["isLocaldbSaving"] = True - local.Run() + local.db.config.logLevel = "debug" + local.db.config.isLocaldbSaving = False + local.run() #end define def PreUp(): CheckMytonctrlUpdate() + check_vport() # CheckTonUpdate() usePool = ton.GetSettings("usePool") useController = ton.GetSettings("useController") @@ -134,6 +136,52 @@ def GetItemFromList(data, index): except: pass #end define +def check_vport(): + vconfig = ton.GetValidatorConfig() + addr = vconfig.addrs.pop() + ip = int2ip(addr.ip) + with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client_socket: + result = client_socket.connect_ex((ip, addr.port)) + if result != 0: + color_print(local.translate("vport_error")) +#end define + +def check_git(input_args, default_repo, text): + src_dir = "/usr/src" + 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") + 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") + #end if + + if need_author is None: + need_author = local_author + if need_repo is None: + need_repo = local_repo + 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) @@ -155,76 +203,65 @@ def GetAuthorRepoBranchFromArgs(args): #end define def Update(args): - # add safe directory to git - gitPath = "/usr/src/mytonctrl" - subprocess.run(["git", "config", "--global", "--add", "safe.directory", gitPath]) - - # Get author, repo, branch - author, repo = GetGitAuthorAndRepo(gitPath) - branch = GetGitBranch(gitPath) - - # Set author, repo, branch - data = GetAuthorRepoBranchFromArgs(args) - author = data.get("author", author) - repo = data.get("repo", repo) - branch = data.get("branch", branch) + 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] - exitCode = RunAsRoot(runArgs) + exitCode = run_as_root(runArgs) if exitCode == 0: text = "Update - {green}OK{endc}" else: text = "Update - {red}Error{endc}" - ColorPrint(text) - local.Exit() + color_print(text) + local.exit() #end define def Upgrade(args): - # add safe directory to git - gitPath = "/usr/src/ton" - subprocess.run(["git", "config", "--global", "--add", "safe.directory", gitPath]) - - # Get author, repo, branch - author, repo = GetGitAuthorAndRepo(gitPath) - branch = GetGitBranch(gitPath) - - # Set author, repo, branch - data = GetAuthorRepoBranchFromArgs(args) - author = data.get("author", author) - repo = data.get("repo", repo) - branch = data.get("branch", branch) + 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") + pubkeyPath = liteClient.get("liteServer").get("pubkeyPath") + if "ton-lite-client-test1" in configPath: + liteClient["configPath"] = configPath.replace("lite-client/ton-lite-client-test1.config.json", "global.config.json") + if "/usr/bin/ton" in pubkeyPath: + liteClient["liteServer"]["pubkeyPath"] = "/var/ton-work/keys/liteserver.pub" + ton.SetSettings("liteClient", liteClient) + validatorConsole = ton.GetSettings("validatorConsole") + privKeyPath = validatorConsole.get("privKeyPath") + pubKeyPath = validatorConsole.get("pubKeyPath") + if "/usr/bin/ton" in privKeyPath: + validatorConsole["privKeyPath"] = "/var/ton-work/keys/client" + 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] - exitCode = RunAsRoot(runArgs) + 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: text = "Upgrade - {red}Error{endc}" - ColorPrint(text) + color_print(text) #end define def CheckMytonctrlUpdate(): - gitPath = local.buffer.get("myDir") - result = CheckGitUpdate(gitPath) + git_path = local.buffer.my_dir + result = check_git_update(git_path) if result is True: - ColorPrint(local.Translate("mytonctrl_update_available")) + color_print(local.translate("mytonctrl_update_available")) #end define def CheckTonUpdate(): - gitPath = "/usr/src/ton" - result = CheckGitUpdate(gitPath) + git_path = "/usr/src/ton" + result = check_git_update(git_path) if result is True: - ColorPrint(local.Translate("ton_update_available")) -#end define - -def PrintTest(args): - print(json.dumps(local.buffer, indent=2)) -#end define - -def sl(args): - Slashing(ton) + color_print(local.translate("ton_update_available")) #end define def PrintStatus(args): @@ -238,9 +275,11 @@ def PrintStatus(args): totalValidators = config34["totalValidators"] onlineValidators = None validatorEfficiency = None + validatorEfficiency2 = None if opt != "fast": onlineValidators = ton.GetOnlineValidators() validatorEfficiency = ton.GetValidatorEfficiency() + validatorEfficiency2 = ton.GetValidatorEfficiency2() if onlineValidators: onlineValidators = len(onlineValidators) oldStartWorkTime = config36.get("startWorkTime") @@ -271,7 +310,7 @@ def PrintStatus(args): 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) + PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorEfficiency2, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg) PrintTonConfig(fullConfigAddr, fullElectorAddr, config15, config17) PrintTimes(rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) #end define @@ -285,28 +324,28 @@ def PrintTonStatus(startWorkTime, totalValidators, onlineValidators, shardsNumbe allOffers = offersNumber.get("all") newComplaints = complaintsNumber.get("new") allComplaints = complaintsNumber.get("all") - tps1_text = bcolors.Green(tps1) - tps5_text = bcolors.Green(tps5) - tps15_text = bcolors.Green(tps15) - tps_text = local.Translate("ton_status_tps").format(tps1_text, tps5_text, tps15_text) + tps1_text = bcolors.green_text(tps1) + tps5_text = bcolors.green_text(tps5) + tps15_text = bcolors.green_text(tps15) + tps_text = local.translate("ton_status_tps").format(tps1_text, tps5_text, tps15_text) onlineValidators_text = GetColorInt(onlineValidators, border=allValidators*2/3, logic="more") - allValidators_text = bcolors.Yellow(allValidators) - validators_text = local.Translate("ton_status_validators").format(onlineValidators_text, allValidators_text) - shards_text = local.Translate("ton_status_shards").format(bcolors.Green(shardsNumber)) - newOffers_text = bcolors.Green(newOffers) - allOffers_text = bcolors.Yellow(allOffers) - offers_text = local.Translate("ton_status_offers").format(newOffers_text, allOffers_text) - newComplaints_text = bcolors.Green(newComplaints) - allComplaints_text = bcolors.Yellow(allComplaints) - complaints_text = local.Translate("ton_status_complaints").format(newComplaints_text, allComplaints_text) + allValidators_text = bcolors.yellow_text(allValidators) + validators_text = local.translate("ton_status_validators").format(onlineValidators_text, allValidators_text) + shards_text = local.translate("ton_status_shards").format(bcolors.green_text(shardsNumber)) + newOffers_text = bcolors.green_text(newOffers) + allOffers_text = bcolors.yellow_text(allOffers) + offers_text = local.translate("ton_status_offers").format(newOffers_text, allOffers_text) + newComplaints_text = bcolors.green_text(newComplaints) + allComplaints_text = bcolors.yellow_text(allComplaints) + complaints_text = local.translate("ton_status_complaints").format(newComplaints_text, allComplaints_text) if startWorkTime == 0: - election_text = bcolors.Yellow("closed") + election_text = bcolors.yellow_text("closed") else: - election_text = bcolors.Green("open") - election_text = local.Translate("ton_status_election").format(election_text) + election_text = bcolors.green_text("open") + election_text = local.translate("ton_status_election").format(election_text) - ColorPrint(local.Translate("ton_status_head")) + color_print(local.translate("ton_status_head")) print(tps_text) print(validators_text) print(shards_text) @@ -316,13 +355,13 @@ 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(adnlAddr, validatorIndex, validatorEfficiency, validatorEfficiency2, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg): if validatorWallet is None: return walletAddr = validatorWallet.addrB64 walletBalance = validatorAccount.balance cpuNumber = psutil.cpu_count() - loadavg = GetLoadAvg() + loadavg = get_load_avg() cpuLoad1 = loadavg[0] cpuLoad5 = loadavg[1] cpuLoad15 = loadavg[2] @@ -332,19 +371,21 @@ def PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWal validatorOutOfSync = validatorStatus.get("outOfSync") validatorIndex_text = GetColorInt(validatorIndex, 0, logic="more") - validatorIndex_text = local.Translate("local_status_validator_index").format(validatorIndex_text) + validatorIndex_text = local.translate("local_status_validator_index").format(validatorIndex_text) validatorEfficiency_text = GetColorInt(validatorEfficiency, 10, logic="more", ending=" %") - validatorEfficiency_text = local.Translate("local_status_validator_efficiency").format(validatorEfficiency_text) - adnlAddr_text = local.Translate("local_status_adnl_addr").format(bcolors.Yellow(adnlAddr)) - walletAddr_text = local.Translate("local_status_wallet_addr").format(bcolors.Yellow(walletAddr)) - walletBalance_text = local.Translate("local_status_wallet_balance").format(bcolors.Green(walletBalance)) + validatorEfficiency_text = local.translate("local_status_validator_efficiency").format(validatorEfficiency_text) + validatorEfficiency2_text = f"{bcolors.cyan}{validatorEfficiency2}{bcolors.endc}" + validatorEfficiency2_text = local.translate("local_status_validator_efficiency_ver2").format(validatorEfficiency2_text) + adnlAddr_text = local.translate("local_status_adnl_addr").format(bcolors.yellow_text(adnlAddr)) + walletAddr_text = local.translate("local_status_wallet_addr").format(bcolors.yellow_text(walletAddr)) + walletBalance_text = local.translate("local_status_wallet_balance").format(bcolors.green_text(walletBalance)) # CPU status - cpuNumber_text = bcolors.Yellow(cpuNumber) + cpuNumber_text = bcolors.yellow_text(cpuNumber) cpuLoad1_text = GetColorInt(cpuLoad1, cpuNumber, logic="less") cpuLoad5_text = GetColorInt(cpuLoad5, cpuNumber, logic="less") cpuLoad15_text = GetColorInt(cpuLoad15, cpuNumber, logic="less") - cpuLoad_text = local.Translate("local_status_cpu_load").format(cpuNumber_text, cpuLoad1_text, cpuLoad5_text, cpuLoad15_text) + cpuLoad_text = local.translate("local_status_cpu_load").format(cpuNumber_text, cpuLoad1_text, cpuLoad5_text, cpuLoad15_text) # Memory status ramUsage = memoryInfo.get("usage") @@ -359,20 +400,20 @@ def PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWal ramLoad_text = ramLoad_text.format(cyan=bcolors.cyan, default=bcolors.default, endc=bcolors.endc, data=ramUsage_text, percent=ramUsagePercent_text) swapLoad_text = "{cyan}swap:[{default}{data}, {percent}{cyan}]{endc}" swapLoad_text = swapLoad_text.format(cyan=bcolors.cyan, default=bcolors.default, endc=bcolors.endc, data=swapUsage_text, percent=swapUsagePercent_text) - memoryLoad_text = local.Translate("local_status_memory").format(ramLoad_text, swapLoad_text) + memoryLoad_text = local.translate("local_status_memory").format(ramLoad_text, swapLoad_text) # Network status netLoad1_text = GetColorInt(netLoad1, 300, logic="less") netLoad5_text = GetColorInt(netLoad5, 300, logic="less") netLoad15_text = GetColorInt(netLoad15, 300, logic="less") - netLoad_text = local.Translate("local_status_net_load").format(netLoad1_text, netLoad5_text, netLoad15_text) + netLoad_text = local.translate("local_status_net_load").format(netLoad1_text, netLoad5_text, netLoad15_text) # Disks status disksLoad_data = list() for key, item in disksLoadAvg.items(): - diskLoad1_text = bcolors.Green(item[0]) - diskLoad5_text = bcolors.Green(item[1]) - diskLoad15_text = bcolors.Green(item[2]) + diskLoad1_text = bcolors.green_text(item[0]) + diskLoad5_text = bcolors.green_text(item[1]) + 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="%") diskLoadPercent15_text = GetColorInt(disksLoadPercentAvg[key][2], 80, logic="less", ending="%") @@ -381,41 +422,43 @@ def PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWal disksLoad_buff = buff.format(diskLoad15_text, diskLoadPercent15_text) disksLoad_data.append(disksLoad_buff) disksLoad_data = ", ".join(disksLoad_data) - disksLoad_text = local.Translate("local_status_disks_load").format(disksLoad_data) + disksLoad_text = local.translate("local_status_disks_load").format(disksLoad_data) # Thread status - mytoncoreStatus_bool = GetServiceStatus("mytoncore") - validatorStatus_bool = GetServiceStatus("validator") - mytoncoreUptime = GetServiceUptime("mytoncore") - validatorUptime = GetServiceUptime("validator") - mytoncoreUptime_text = bcolors.Green(time2human(mytoncoreUptime)) - validatorUptime_text = bcolors.Green(time2human(validatorUptime)) + mytoncoreStatus_bool = get_service_status("mytoncore") + validatorStatus_bool = get_service_status("validator") + mytoncoreUptime = get_service_uptime("mytoncore") + validatorUptime = get_service_uptime("validator") + mytoncoreUptime_text = bcolors.green_text(time2human(mytoncoreUptime)) + validatorUptime_text = bcolors.green_text(time2human(validatorUptime)) mytoncoreStatus = GetColorStatus(mytoncoreStatus_bool) validatorStatus = GetColorStatus(validatorStatus_bool) - mytoncoreStatus_text = local.Translate("local_status_mytoncore_status").format(mytoncoreStatus, mytoncoreUptime_text) - validatorStatus_text = local.Translate("local_status_validator_status").format(validatorStatus, validatorUptime_text) - validatorOutOfSync_text = local.Translate("local_status_validator_out_of_sync").format(GetColorInt(validatorOutOfSync, 20, logic="less", ending=" s")) + mytoncoreStatus_text = local.translate("local_status_mytoncore_status").format(mytoncoreStatus, mytoncoreUptime_text) + validatorStatus_text = local.translate("local_status_validator_status").format(validatorStatus, validatorUptime_text) + validatorOutOfSync_text = local.translate("local_status_validator_out_of_sync").format(GetColorInt(validatorOutOfSync, 20, logic="less", ending=" s")) dbSize_text = GetColorInt(dbSize, 1000, logic="less", ending=" Gb") dbUsage_text = GetColorInt(dbUsage, 80, logic="less", ending="%") - dbStatus_text = local.Translate("local_status_db").format(dbSize_text, dbUsage_text) + dbStatus_text = local.translate("local_status_db").format(dbSize_text, dbUsage_text) # Mytonctrl and validator git hash mtcGitPath = "/usr/src/mytonctrl" validatorGitPath = "/usr/src/ton" - mtcGitHash = GetGitHash(mtcGitPath, short=True) - validatorGitHash = GetGitHash(validatorGitPath, short=True) - mtcGitBranch = GetGitBranch(mtcGitPath) - validatorGitBranch = GetGitBranch(validatorGitPath) - mtcGitHash_text = bcolors.Yellow(mtcGitHash) - validatorGitHash_text = bcolors.Yellow(validatorGitHash) - mtcGitBranch_text = bcolors.Yellow(mtcGitBranch) - validatorGitBranch_text = bcolors.Yellow(validatorGitBranch) - mtcVersion_text = local.Translate("local_status_version_mtc").format(mtcGitHash_text, mtcGitBranch_text) - validatorVersion_text = local.Translate("local_status_version_validator").format(validatorGitHash_text, validatorGitBranch_text) - - ColorPrint(local.Translate("local_status_head")) + validatorBinGitPath = "/usr/bin/ton/validator-engine/validator-engine" + mtcGitHash = get_git_hash(mtcGitPath, short=True) + validatorGitHash = GetBinGitHash(validatorBinGitPath, short=True) + mtcGitBranch = get_git_branch(mtcGitPath) + validatorGitBranch = get_git_branch(validatorGitPath) + mtcGitHash_text = bcolors.yellow_text(mtcGitHash) + validatorGitHash_text = bcolors.yellow_text(validatorGitHash) + mtcGitBranch_text = bcolors.yellow_text(mtcGitBranch) + validatorGitBranch_text = bcolors.yellow_text(validatorGitBranch) + mtcVersion_text = local.translate("local_status_version_mtc").format(mtcGitHash_text, mtcGitBranch_text) + validatorVersion_text = local.translate("local_status_version_validator").format(validatorGitHash_text, validatorGitBranch_text) + + color_print(local.translate("local_status_head")) print(validatorIndex_text) print(validatorEfficiency_text) + print(validatorEfficiency2_text) print(adnlAddr_text) print(walletAddr_text) print(walletBalance_text) @@ -435,25 +478,25 @@ def PrintLocalStatus(adnlAddr, validatorIndex, validatorEfficiency, validatorWal def GetColorInt(data, border, logic, ending=None): if data is None: - result = bcolors.Green("n/a") + result = bcolors.green_text("n/a") elif logic == "more": if data >= border: - result = bcolors.Green(data, ending) + result = bcolors.green_text(data, ending) else: - result = bcolors.Red(data, ending) + result = bcolors.red_text(data, ending) elif logic == "less": if data <= border: - result = bcolors.Green(data, ending) + result = bcolors.green_text(data, ending) else: - result = bcolors.Red(data, ending) + result = bcolors.red_text(data, ending) return result #end define def GetColorStatus(input): if input == True: - result = bcolors.Green("working") + result = bcolors.green_text("working") else: - result = bcolors.Red("not working") + result = bcolors.red_text("not working") return result #end define @@ -465,18 +508,18 @@ def PrintTonConfig(fullConfigAddr, fullElectorAddr, config15, config17): minStake = config17["minStake"] maxStake = config17["maxStake"] - fullConfigAddr_text = local.Translate("ton_config_configurator_addr").format(bcolors.Yellow(fullConfigAddr)) - fullElectorAddr_text = local.Translate("ton_config_elector_addr").format(bcolors.Yellow(fullElectorAddr)) - validatorsElectedFor_text = bcolors.Yellow(validatorsElectedFor) - electionsStartBefore_text = bcolors.Yellow(electionsStartBefore) - electionsEndBefore_text = bcolors.Yellow(electionsEndBefore) - stakeHeldFor_text = bcolors.Yellow(stakeHeldFor) - elections_text = local.Translate("ton_config_elections").format(validatorsElectedFor_text, electionsStartBefore_text, electionsEndBefore_text, stakeHeldFor_text) - minStake_text = bcolors.Yellow(minStake) - maxStake_text = bcolors.Yellow(maxStake) - stake_text = local.Translate("ton_config_stake").format(minStake_text, maxStake_text) - - ColorPrint(local.Translate("ton_config_head")) + fullConfigAddr_text = local.translate("ton_config_configurator_addr").format(bcolors.yellow_text(fullConfigAddr)) + fullElectorAddr_text = local.translate("ton_config_elector_addr").format(bcolors.yellow_text(fullElectorAddr)) + validatorsElectedFor_text = bcolors.yellow_text(validatorsElectedFor) + electionsStartBefore_text = bcolors.yellow_text(electionsStartBefore) + electionsEndBefore_text = bcolors.yellow_text(electionsEndBefore) + stakeHeldFor_text = bcolors.yellow_text(stakeHeldFor) + elections_text = local.translate("ton_config_elections").format(validatorsElectedFor_text, electionsStartBefore_text, electionsEndBefore_text, stakeHeldFor_text) + minStake_text = bcolors.yellow_text(minStake) + maxStake_text = bcolors.yellow_text(maxStake) + stake_text = local.translate("ton_config_stake").format(minStake_text, maxStake_text) + + color_print(local.translate("ton_config_head")) print(fullConfigAddr_text) print(fullElectorAddr_text) print(elections_text) @@ -501,22 +544,22 @@ def PrintTimes(rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, co startNextElection = startElection + validatorsElectedFor # timestamp to datetime - rootWorkchainEnabledTime = Timestamp2Datetime(rootWorkchainEnabledTime_int) - startValidationTime = Timestamp2Datetime(startValidation) - endValidationTime = Timestamp2Datetime(endValidation) - startElectionTime = Timestamp2Datetime(startElection) - endElectionTime = Timestamp2Datetime(endElection) - startNextElectionTime = Timestamp2Datetime(startNextElection) + rootWorkchainEnabledTime = timestamp2datetime(rootWorkchainEnabledTime_int) + startValidationTime = timestamp2datetime(startValidation) + endValidationTime = timestamp2datetime(endValidation) + startElectionTime = timestamp2datetime(startElection) + endElectionTime = timestamp2datetime(endElection) + startNextElectionTime = timestamp2datetime(startNextElection) # datetime to color text - rootWorkchainEnabledTime_text = local.Translate("times_root_workchain_enabled_time").format(bcolors.Yellow(rootWorkchainEnabledTime)) - startValidationTime_text = local.Translate("times_start_validation_time").format(GetColorTime(startValidationTime, startValidation)) - endValidationTime_text = local.Translate("times_end_validation_time").format(GetColorTime(endValidationTime, endValidation)) - startElectionTime_text = local.Translate("times_start_election_time").format(GetColorTime(startElectionTime, startElection)) - endElectionTime_text = local.Translate("times_end_election_time").format(GetColorTime(endElectionTime, endElection)) - startNextElectionTime_text = local.Translate("times_start_next_election_time").format(GetColorTime(startNextElectionTime, startNextElection)) - - ColorPrint(local.Translate("times_head")) + rootWorkchainEnabledTime_text = local.translate("times_root_workchain_enabled_time").format(bcolors.yellow_text(rootWorkchainEnabledTime)) + startValidationTime_text = local.translate("times_start_validation_time").format(GetColorTime(startValidationTime, startValidation)) + endValidationTime_text = local.translate("times_end_validation_time").format(GetColorTime(endValidationTime, endValidation)) + startElectionTime_text = local.translate("times_start_election_time").format(GetColorTime(startElectionTime, startElection)) + endElectionTime_text = local.translate("times_end_election_time").format(GetColorTime(endElectionTime, endElection)) + startNextElectionTime_text = local.translate("times_start_next_election_time").format(GetColorTime(startNextElectionTime, startNextElection)) + + color_print(local.translate("times_head")) print(rootWorkchainEnabledTime_text) print(startValidationTime_text) print(endValidationTime_text) @@ -526,11 +569,11 @@ def PrintTimes(rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, co #end define def GetColorTime(datetime, timestamp): - newTimestamp = GetTimestamp() + newTimestamp = get_timestamp() if timestamp > newTimestamp: - result = bcolors.Green(datetime) + result = bcolors.green_text(datetime) else: - result = bcolors.Yellow(datetime) + result = bcolors.yellow_text(datetime) return result #end define @@ -538,7 +581,7 @@ def Seqno(args): try: walletName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} seqno ") + color_print("{red}Bad args. Usage:{endc} seqno ") return wallet = ton.GetLocalWallet(walletName) seqno = ton.GetSeqno(wallet) @@ -561,13 +604,13 @@ def CreatNewWallet(args): else: subwallet = 698983191 + workchain # 0x29A9A317 + workchain except: - ColorPrint("{red}Bad args. Usage:{endc} nw [ ]") + color_print("{red}Bad args. Usage:{endc} nw [ ]") return wallet = ton.CreateWallet(walletName, workchain, version, subwallet=subwallet) table = list() table += [["Name", "Workchain", "Address"]] table += [[wallet.name, wallet.workchain, wallet.addrB64_init]] - PrintTable(table) + print_table(table) #end define def ActivateWallet(args): @@ -580,10 +623,10 @@ def ActivateWallet(args): else: wallet = ton.GetLocalWallet(walletName) if not os.path.isfile(wallet.bocFilePath): - local.AddLog("Wallet {walletName} already activated".format(walletName=walletName), "warning") + local.add_log("Wallet {walletName} already activated".format(walletName=walletName), "warning") return ton.ActivateWallet(wallet) - ColorPrint("ActivateWallet - {green}OK{endc}") + color_print("ActivateWallet - {green}OK{endc}") #end define def PrintWalletsList(args): @@ -598,24 +641,24 @@ 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]] - PrintTable(table) + print_table(table) #end define def ImportWalletFromFile(args): try: filePath = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} iw ") + color_print("{red}Bad args. Usage:{endc} iw ") return if (".addr" in filePath): filePath = filePath.replace(".addr", '') if (".pk" in filePath): filePath = filePath.replace(".pk", '') if os.path.isfile(filePath + ".addr") == False: - local.AddLog("ImportWalletFromFile error: Address file not found: " + filePath, "error") + local.add_log("ImportWalletFromFile error: Address file not found: " + filePath, "error") return if os.path.isfile(filePath + ".pk") == False: - local.AddLog("ImportWalletFromFile error: Private key not found: " + filePath, "error") + local.add_log("ImportWalletFromFile error: Private key not found: " + filePath, "error") return if '/' in filePath: walletName = filePath[filePath.rfind('/')+1:] @@ -623,7 +666,7 @@ def ImportWalletFromFile(args): walletName = filePath copyfile(filePath + ".addr", ton.walletsDir + walletName + ".addr") copyfile(filePath + ".pk", ton.walletsDir + walletName + ".pk") - ColorPrint("ImportWalletFromFile - {green}OK{endc}") + color_print("ImportWalletFromFile - {green}OK{endc}") #end define def ImportWallet(args): @@ -631,7 +674,7 @@ def ImportWallet(args): addr = args[0] key = args[1] except: - ColorPrint("{red}Bad args. Usage:{endc} iw ") + color_print("{red}Bad args. Usage:{endc} iw ") return name = ton.ImportWallet(addr, key) print("Wallet name:", name) @@ -642,17 +685,17 @@ def SetWalletVersion(args): addr = args[0] version = args[1] except: - ColorPrint("{red}Bad args. Usage:{endc} swv ") + color_print("{red}Bad args. Usage:{endc} swv ") return ton.SetWalletVersion(addr, version) - ColorPrint("SetWalletVersion - {green}OK{endc}") + color_print("SetWalletVersion - {green}OK{endc}") #end define def ExportWallet(args): try: name = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} ew ") + color_print("{red}Bad args. Usage:{endc} ew ") return addr, key = ton.ExportWallet(name) print("Wallet name:", name) @@ -664,18 +707,21 @@ def DeleteWallet(args): try: walletName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} dw ") + color_print("{red}Bad args. Usage:{endc} dw ") + return + if input("Are you sure you want to delete this wallet (yes/no): ") != "yes": + print("Cancel wallet deletion") return wallet = ton.GetLocalWallet(walletName) wallet.Delete() - ColorPrint("DeleteWallet - {green}OK{endc}") + color_print("DeleteWallet - {green}OK{endc}") #end define def ViewAccountStatus(args): try: addrB64 = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} vas ") + color_print("{red}Bad args. Usage:{endc} vas ") return addrB64 = ton.GetDestinationAddr(addrB64) account = ton.GetAccount(addrB64) @@ -684,10 +730,9 @@ def ViewAccountStatus(args): statusTable += [["Address", "Status", "Version", "Balance"]] statusTable += [[addrB64, account.status, version, account.balance]] historyTable = GetHistoryTable(addrB64, 10) - PrintTable(statusTable) - ColorPrint("{yellow}codeHash: " + account.codeHash + "{endc}") + print_table(statusTable) print() - PrintTable(historyTable) + print_table(historyTable) #end define def ViewAccountHistory(args): @@ -695,10 +740,10 @@ def ViewAccountHistory(args): addr = args[0] limit = int(args[1]) except: - ColorPrint("{red}Bad args. Usage:{endc} vah ") + color_print("{red}Bad args. Usage:{endc} vah ") return table = GetHistoryTable(addr, limit) - PrintTable(table) + print_table(table) #end define def GetHistoryTable(addr, limit): @@ -706,7 +751,7 @@ def GetHistoryTable(addr, limit): account = ton.GetAccount(addr) history = ton.GetAccountHistory(account, limit) table = list() - typeText = ColorText("{red}{bold}{endc}") + typeText = color_text("{red}{bold}{endc}") table += [["Time", typeText, "Coins", "From/To"]] for message in history: if message.srcAddr is None or message.value is None: @@ -714,13 +759,13 @@ def GetHistoryTable(addr, limit): srcAddrFull = f"{message.srcWorkchain}:{message.srcAddr}" destAddFull = f"{message.destWorkchain}:{message.destAddr}" if srcAddrFull == account.addrFull: - type = ColorText("{red}{bold}>>>{endc}") + type = color_text("{red}{bold}>>>{endc}") fromto = destAddFull else: - type = ColorText("{blue}{bold}<<<{endc}") + type = color_text("{blue}{bold}<<<{endc}") fromto = srcAddrFull fromto = ton.AddrFull2AddrB64(fromto) - #datetime = Timestamp2Datetime(message.time, "%Y.%m.%d %H:%M:%S") + #datetime = timestamp2datetime(message.time, "%Y.%m.%d %H:%M:%S") datetime = timeago(message.time) table += [[datetime, type, message.value, fromto]] return table @@ -733,12 +778,12 @@ def MoveCoins(args): amount = args[2] flags = args[3:] except: - ColorPrint("{red}Bad args. Usage:{endc} mg ") + color_print("{red}Bad args. Usage:{endc} mg ") return wallet = ton.GetLocalWallet(walletName) destination = ton.GetDestinationAddr(destination) ton.MoveCoins(wallet, destination, amount, flags=flags) - ColorPrint("MoveCoins - {green}OK{endc}") + color_print("MoveCoins - {green}OK{endc}") #end define def MoveCoinsThroughProxy(args): @@ -747,12 +792,12 @@ def MoveCoinsThroughProxy(args): destination = args[1] amount = args[2] except: - ColorPrint("{red}Bad args. Usage:{endc} mgtp ") + color_print("{red}Bad args. Usage:{endc} mgtp ") return wallet = ton.GetLocalWallet(walletName) destination = ton.GetDestinationAddr(destination) ton.MoveCoinsThroughProxy(wallet, destination, amount) - ColorPrint("MoveCoinsThroughProxy - {green}OK{endc}") + color_print("MoveCoinsThroughProxy - {green}OK{endc}") #end define def CreatNewBookmark(args): @@ -760,7 +805,7 @@ def CreatNewBookmark(args): name = args[0] addr = args[1] except: - ColorPrint("{red}Bad args. Usage:{endc} nb ") + color_print("{red}Bad args. Usage:{endc} nb ") return if ton.IsAddr(addr): type = "account" @@ -773,7 +818,7 @@ def CreatNewBookmark(args): bookmark["type"] = type bookmark["addr"] = addr ton.AddBookmark(bookmark) - ColorPrint("CreatNewBookmark - {green}OK{endc}") + color_print("CreatNewBookmark - {green}OK{endc}") #end define def PrintBookmarksList(args): @@ -789,7 +834,7 @@ def PrintBookmarksList(args): addr = item.get("addr") data = item.get("data") table += [[name, type, addr, data]] - PrintTable(table) + print_table(table) #end define def DeleteBookmark(args): @@ -797,10 +842,10 @@ def DeleteBookmark(args): name = args[0] type = args[1] except: - ColorPrint("{red}Bad args. Usage:{endc} db ") + color_print("{red}Bad args. Usage:{endc} db ") return ton.DeleteBookmark(name, type) - ColorPrint("DeleteBookmark - {green}OK{endc}") + color_print("DeleteBookmark - {green}OK{endc}") #end define def PrintOffersList(args): @@ -823,20 +868,20 @@ def PrintOffersList(args): if "hash" not in args: hash = Reduct(hash) if isPassed == True: - isPassed = bcolors.Green("true") + isPassed = bcolors.green_text("true") if isPassed == False: - isPassed = bcolors.Red("false") + isPassed = bcolors.red_text("false") table += [[hash, votedValidators, wl, approvedPercent_text, isPassed]] - PrintTable(table) + print_table(table) #end define def VoteOffer(args): if len(args) == 0: - ColorPrint("{red}Bad args. Usage:{endc} vo ") + color_print("{red}Bad args. Usage:{endc} vo ") return for offerHash in args: ton.VoteOffer(offerHash) - ColorPrint("VoteOffer - {green}OK{endc}") + color_print("VoteOffer - {green}OK{endc}") #end define def OfferDiff(args): @@ -844,7 +889,7 @@ def OfferDiff(args): offerHash = args[0] offerHash = offerHash except: - ColorPrint("{red}Bad args. Usage:{endc} od ") + color_print("{red}Bad args. Usage:{endc} od ") return ton.GetOfferDiff(offerHash) #end define @@ -854,7 +899,7 @@ def GetConfig(args): configId = args[0] configId = int(configId) except: - ColorPrint("{red}Bad args. Usage:{endc} gc ") + color_print("{red}Bad args. Usage:{endc} gc ") return data = ton.GetConfig(configId) text = json.dumps(data, indent=2) @@ -883,11 +928,11 @@ def PrintComplaintsList(args): if "adnl" not in args: adnl = Reduct(adnl) if isPassed == True: - isPassed = bcolors.Green("true") + isPassed = bcolors.green_text("true") if isPassed == False: - isPassed = bcolors.Red("false") + isPassed = bcolors.red_text("false") table += [[electionId, adnl, Fine_text, votedValidators, approvedPercent_text, isPassed]] - PrintTable(table) + print_table(table) #end define def VoteComplaint(args): @@ -895,10 +940,10 @@ def VoteComplaint(args): electionId = args[0] complaintHash = args[1] except: - ColorPrint("{red}Bad args. Usage:{endc} vc ") + color_print("{red}Bad args. Usage:{endc} vc ") return ton.VoteComplaint(electionId, complaintHash) - ColorPrint("VoteComplaint - {green}OK{endc}") + color_print("VoteComplaint - {green}OK{endc}") #end define def NewDomain(args): @@ -907,14 +952,14 @@ def NewDomain(args): walletName = args[1] adnlAddr = args[2] except: - ColorPrint("{red}Bad args. Usage:{endc} nd ") + color_print("{red}Bad args. Usage:{endc} nd ") return domain = dict() domain["name"] = domainName domain["adnlAddr"] = adnlAddr domain["walletName"] = walletName ton.NewDomain(domain) - ColorPrint("NewDomain - {green}OK{endc}") + color_print("NewDomain - {green}OK{endc}") #end define def PrintDomainsList(args): @@ -928,36 +973,47 @@ def PrintDomainsList(args): domainName = item.get("name") walletName = item.get("walletName") endTime = item.get("endTime") - endTime = Timestamp2Datetime(endTime, "%d.%m.%Y") + endTime = timestamp2datetime(endTime, "%d.%m.%Y") adnlAddr = item.get("adnlAddr") table += [[domainName, walletName, endTime, adnlAddr]] - PrintTable(table) + print_table(table) #end define def ViewDomainStatus(args): try: domainName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} vds ") + color_print("{red}Bad args. Usage:{endc} vds ") return domain = ton.GetDomain(domainName) endTime = domain.get("endTime") - endTime = Timestamp2Datetime(endTime, "%d.%m.%Y") + endTime = timestamp2datetime(endTime, "%d.%m.%Y") adnlAddr = domain.get("adnlAddr") table = list() table += [["Domain", "Expiration date", "ADNL address"]] table += [[domainName, endTime, adnlAddr]] - PrintTable(table) + print_table(table) #end define def DeleteDomain(args): try: domainName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} dd ") + color_print("{red}Bad args. Usage:{endc} dd ") return ton.DeleteDomain(domainName) - ColorPrint("DeleteDomain - {green}OK{endc}") + color_print("DeleteDomain - {green}OK{endc}") +#end define + +def GetDomainFromAuction(args): + try: + walletName = args[0] + addr = args[1] + except: + color_print("{red}Bad args. Usage:{endc} gdfa ") + return + ton.GetDomainFromAuction(walletName, addr) + color_print("GetDomainFromAuction - {green}OK{endc}") #end define def PrintElectionEntriesList(args): @@ -982,12 +1038,12 @@ def PrintElectionEntriesList(args): if "wallet" not in args: walletAddr = Reduct(walletAddr) table += [[adnl, pubkey, walletAddr, stake, maxFactor]] - PrintTable(table) + print_table(table) #end define def VoteElectionEntry(args): Elections(ton) - ColorPrint("VoteElectionEntry - {green}OK{endc}") + color_print("VoteElectionEntry - {green}OK{endc}") #end define def PrintValidatorList(args): @@ -1014,11 +1070,11 @@ def PrintValidatorList(args): if "offline" in args and online != False: continue if online == True: - online = bcolors.Green("true") + online = bcolors.green_text("true") if online == False: - online = bcolors.Red("false") + online = bcolors.red_text("false") table += [[adnl, pubkey, walletAddr, efficiency, online]] - PrintTable(table) + print_table(table) #end define def Reduct(item): @@ -1035,7 +1091,7 @@ def GetSettings(args): try: name = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} get ") + color_print("{red}Bad args. Usage:{endc} get ") return result = ton.GetSettings(name) print(json.dumps(result, indent=2)) @@ -1046,28 +1102,28 @@ def SetSettings(args): name = args[0] value = args[1] except: - ColorPrint("{red}Bad args. Usage:{endc} set ") + color_print("{red}Bad args. Usage:{endc} set ") return result = ton.SetSettings(name, value) - ColorPrint("SetSettings - {green}OK{endc}") + color_print("SetSettings - {green}OK{endc}") #end define def Xrestart(inputArgs): if len(inputArgs) < 2: - ColorPrint("{red}Bad args. Usage:{endc} xrestart ") + color_print("{red}Bad args. Usage:{endc} xrestart ") return args = ["python3", "/usr/src/mytonctrl/scripts/xrestart.py"] args += inputArgs - exitCode = RunAsRoot(args) + exitCode = run_as_root(args) if exitCode == 0: text = "Xrestart - {green}OK{endc}" else: text = "Xrestart - {red}Error{endc}" - ColorPrint(text) + color_print(text) #end define def Xlist(args): - ColorPrint("Xlist - {green}OK{endc}") + color_print("Xlist - {green}OK{endc}") #end define def NewPool(args): @@ -1078,24 +1134,24 @@ def NewPool(args): minValidatorStake = int(args[3]) minNominatorStake = int(args[4]) except: - ColorPrint("{red}Bad args. Usage:{endc} new_pool ") + color_print("{red}Bad args. Usage:{endc} new_pool ") return ton.CreatePool(poolName, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake) - ColorPrint("NewPool - {green}OK{endc}") + color_print("NewPool - {green}OK{endc}") #end define def ActivatePool(args): try: poolName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} activate_pool ") + color_print("{red}Bad args. Usage:{endc} activate_pool ") return pool = ton.GetLocalPool(poolName) if not os.path.isfile(pool.bocFilePath): - local.AddLog(f"Pool {poolName} already activated", "warning") + local.add_log(f"Pool {poolName} already activated", "warning") return ton.ActivatePool(pool) - ColorPrint("ActivatePool - {green}OK{endc}") + color_print("ActivatePool - {green}OK{endc}") #end define def PrintPoolsList(args): @@ -1110,14 +1166,14 @@ def PrintPoolsList(args): if account.status != "active": pool.addrB64 = pool.addrB64_init table += [[pool.name, account.status, account.balance, pool.addrB64]] - PrintTable(table) + print_table(table) #end define def GetPoolData(args): try: poolName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} get_pool_data ") + color_print("{red}Bad args. Usage:{endc} get_pool_data ") return if ton.IsAddr(poolName): poolAddr = poolName @@ -1134,45 +1190,43 @@ def DepositToPool(args): pollAddr = args[1] amount = float(args[2]) except: - ColorPrint("{red}Bad args. Usage:{endc} deposit_to_pool ") + color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") return ton.DepositToPool(walletName, pollAddr, amount) - ColorPrint("DepositToPool - {green}OK{endc}") + color_print("DepositToPool - {green}OK{endc}") #end define def WithdrawFromPool(args): try: - walletName = args[0] - poolAddr = args[1] - amount = float(args[2]) + poolAddr = args[0] + amount = float(args[1]) except: - ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_pool ") + color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") return - poolAddr = ton.GetDestinationAddr(poolAddr) - ton.WithdrawFromPool(walletName, poolAddr, amount) - ColorPrint("WithdrawFromPool - {green}OK{endc}") + ton.WithdrawFromPool(poolAddr, amount) + color_print("WithdrawFromPool - {green}OK{endc}") #end define def DeletePool(args): try: poolName = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} delete_pool ") + color_print("{red}Bad args. Usage:{endc} delete_pool ") return pool = ton.GetLocalPool(poolName) pool.Delete() - ColorPrint("DeletePool - {green}OK{endc}") + color_print("DeletePool - {green}OK{endc}") #end define def PoolUpdateValidatorSet(args): try: poolAddr = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} pool_update_validator_set ") + color_print("{red}Bad args. Usage:{endc} pool_update_validator_set ") return wallet = ton.GetValidatorWallet() ton.PoolUpdateValidatorSet(poolAddr, wallet) - ColorPrint("PoolUpdateValidatorSet - {green}OK{endc}") + color_print("PoolUpdateValidatorSet - {green}OK{endc}") #end define def CreateControllers(args): diff --git a/mytoninstaller.py b/mytoninstaller.py index a97477d3..6b5916c9 100644 --- a/mytoninstaller.py +++ b/mytoninstaller.py @@ -13,19 +13,19 @@ 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 + 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) + 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" @@ -42,49 +42,43 @@ def Init(): #end define def Refresh(): - user = local.buffer["user"] - local.buffer["mconfigPath"] = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) + user = local.buffer.user + local.buffer.mconfig_path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) if user == 'root': - local.buffer["mconfigPath"] = "/usr/local/bin/mytoncore/mytoncore.db" + local.buffer.mconfig_path = "/usr/local/bin/mytoncore/mytoncore.db" #end if # create variables - binDir = "/usr/bin/" - srcDir = "/usr/src/" - tonWorkDir = "/var/ton-work/" - tonBinDir = binDir + "ton/" - tonSrcDir = srcDir + "ton/" - local.buffer["binDir"] = binDir - local.buffer["srcDir"] = srcDir - local.buffer["tonWorkDir"] = tonWorkDir - local.buffer["tonBinDir"] = tonBinDir - local.buffer["tonSrcDir"] = tonSrcDir - tonDbDir = tonWorkDir + "db/" - keysDir = tonWorkDir + "keys/" - local.buffer["tonDbDir"] = tonDbDir - local.buffer["keysDir"] = keysDir - local.buffer["tonLogPath"] = tonWorkDir + "log" - local.buffer["validatorAppPath"] = tonBinDir + "validator-engine/validator-engine" - local.buffer["globalConfigPath"] = tonBinDir + "global.config.json" - local.buffer["vconfigPath"] = tonDbDir + "config.json" + 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): - vconfigPath = local.buffer["vconfigPath"] - - user = local.buffer["user"] - mconfigPath = local.buffer["mconfigPath"] - - tonBinDir = local.buffer["tonBinDir"] - keysDir = local.buffer["keysDir"] - server_key = keysDir + "server" - client_key = keysDir + "client" - liteserver_key = keysDir + "liteserver" + 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(vconfigPath) - mtcStatus = os.path.isfile(mconfigPath) + 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) @@ -96,38 +90,39 @@ def Status(args): def Enable(args): name = args[0] - user = local.buffer["user"] if name == "THA": CreateLocalConfigFile(args, localhost=True) - args = ["python3", local.buffer["myPath"], "-u", user, "-e", "enable{name}".format(name=name)] - RunAsRoot(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): - user = local.buffer["user"] - args = ["python3", local.buffer["myPath"], "-u", user, "-e", "drvcf"] - RunAsRoot(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(): - keysDir = local.buffer["keysDir"] - liteserver_key = keysDir + "liteserver" + keys_dir = local.buffer.keys_dir + liteserver_key = keys_dir + "liteserver" liteserver_pubkey = liteserver_key + ".pub" - result = dict() + result = Dict() file = open(liteserver_pubkey, 'rb') data = file.read() file.close() key = base64.b64encode(data[4:]) - ip = requests.get("https://ifconfig.me").text - mconfigPath = local.buffer["mconfigPath"] - mconfig = GetConfig(path=mconfigPath) - liteClient = mconfig.get("liteClient") - liteServer = liteClient.get("liteServer") - result["ip"] = ip2int(ip) - result["port"] = liteServer.get("port") - result["id"] = dict() - result["id"]["@type"]= "pub.ed25519" - result["id"]["key"]= key.decode() + 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 @@ -165,7 +160,7 @@ def CreateLocalConfig(initBlock, localConfigPath=defaultLocalConfigPath, localho file.close() # chown - user = local.buffer["user"] + user = local.buffer.user args = ["chown", "-R", user + ':' + user, localConfigPath] print("Local config file created:", localConfigPath) @@ -184,9 +179,8 @@ def CreateLocalConfigFile(args, localhost=False): event_name = "clc" initBlock = GetInitBlock() initBlock_b64 = dict2b64(initBlock) - user = local.buffer["user"] - args = ["python3", local.buffer["myPath"], "-u", user, "-e", event_name, "-i", initBlock_b64] - RunAsRoot(args) + args = ["python3", local.buffer.my_path, "-u", local.buffer.user, "-e", event_name, "-i", initBlock_b64] + run_as_root(args) #end define def Event(name): @@ -202,9 +196,9 @@ def Event(name): DangerousRecoveryValidatorConfigFile() if name == "enableJR": EnableJsonRpc() - if name == "enableTHA": - EnableTonHttpApi() - if name in ["clc", "clcl"]: + if name == "enablePT": + EnablePytonv3() + if name == "clc": ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] initBlock = b642dict(initBlock_b64) @@ -218,7 +212,7 @@ def General(): if "-u" in sys.argv: ux = sys.argv.index("-u") user = sys.argv[ux+1] - local.buffer["user"] = user + local.buffer.user = user Refresh() if "-e" in sys.argv: ex = sys.argv.index("-e") @@ -230,11 +224,11 @@ def General(): if "-t" in sys.argv: mx = sys.argv.index("-t") telemetry = sys.argv[mx+1] - local.buffer["telemetry"] = Str2Bool(telemetry) + 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) + local.buffer.dump = Str2Bool(dump) #end if # Создать настройки для mytoncore.py @@ -260,22 +254,22 @@ def Str2Bool(str): #end define def FirstNodeSettings(): - local.AddLog("start FirstNodeSettings fuction", "debug") + local.add_log("start FirstNodeSettings fuction", "debug") # Создать переменные - user = local.buffer["user"] - vuser = local.buffer["vuser"] - tonWorkDir = local.buffer["tonWorkDir"] - tonDbDir = local.buffer["tonDbDir"] - keysDir = local.buffer["keysDir"] - tonLogPath = local.buffer["tonLogPath"] - validatorAppPath = local.buffer["validatorAppPath"] - globalConfigPath = local.buffer["globalConfigPath"] - vconfigPath = local.buffer["vconfigPath"] + user = local.buffer.user + vuser = local.buffer.vuser + ton_work_dir = local.buffer.ton_work_dir + ton_db_dir = local.buffer.ton_db_dir + keys_dir = local.buffer.keys_dir + tonLogPath = local.buffer.ton_log_path + validatorAppPath = local.buffer.validator_app_path + globalConfigPath = local.buffer.global_config_path + vconfig_path = local.buffer.vconfig_path # Проверить конфигурацию - if os.path.isfile(vconfigPath): - local.AddLog("Validators config.json already exist. Break FirstNodeSettings fuction", "warning") + if os.path.isfile(vconfig_path): + local.add_log("Validators config.json already exist. Break FirstNodeSettings fuction", "warning") return #end if @@ -284,38 +278,38 @@ def FirstNodeSettings(): text = file.read() file.close() if vuser not in text: - local.AddLog("Creating new user: " + vuser, "debug") + local.add_log("Creating new user: " + vuser, "debug") args = ["/usr/sbin/useradd", "-d", "/dev/null", "-s", "/dev/null", vuser] subprocess.run(args) #end if # Подготовить папки валидатора - os.makedirs(tonDbDir, exist_ok=True) - os.makedirs(keysDir, exist_ok=True) + os.makedirs(ton_db_dir, exist_ok=True) + os.makedirs(keys_dir, exist_ok=True) # Прописать автозагрузку cpus = psutil.cpu_count() - 1 - cmd = "{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {tonDbDir} --logname {tonLogPath} --state-ttl 604800 --verbosity 1" - cmd = cmd.format(validatorAppPath=validatorAppPath, globalConfigPath=globalConfigPath, tonDbDir=tonDbDir, tonLogPath=tonLogPath, cpus=cpus) - Add2Systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" + cmd = "{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --verbosity 1" + cmd = cmd.format(validatorAppPath=validatorAppPath, globalConfigPath=globalConfigPath, ton_db_dir=ton_db_dir, tonLogPath=tonLogPath, cpus=cpus) + add2systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" # Получить внешний ip адрес - ip = requests.get("https://ifconfig.me").text + ip = get_own_ip() vport = random.randint(2000, 65000) addr = "{ip}:{vport}".format(ip=ip, vport=vport) - local.AddLog("Use addr: " + addr, "debug") + local.add_log("Use addr: " + addr, "debug") # Первый запуск - local.AddLog("First start validator - create config.json", "debug") - args = [validatorAppPath, "--global-config", globalConfigPath, "--db", tonDbDir, "--ip", addr, "--logname", tonLogPath] + local.add_log("First start validator - create config.json", "debug") + args = [validatorAppPath, "--global-config", globalConfigPath, "--db", ton_db_dir, "--ip", addr, "--logname", tonLogPath] subprocess.run(args) # Скачать дамп DownloadDump() # chown 1 - local.AddLog("Chown ton-work dir", "debug") - args = ["chown", "-R", vuser + ':' + vuser, tonWorkDir] + local.add_log("Chown ton-work dir", "debug") + args = ["chown", "-R", vuser + ':' + vuser, ton_work_dir] subprocess.run(args) # start validator @@ -323,12 +317,12 @@ def FirstNodeSettings(): #end define def DownloadDump(): - dump = local.buffer["dump"] + dump = local.buffer.dump if dump == False: return #end if - local.AddLog("start DownloadDump fuction", "debug") + local.add_log("start DownloadDump fuction", "debug") url = "https://dump.ton.org" dumpSize = requests.get(url + "/dumps/latest.size.archive.txt").text print("dumpSize:", dumpSize) @@ -348,17 +342,17 @@ def DownloadDump(): #end define def FirstMytoncoreSettings(): - local.AddLog("start FirstMytoncoreSettings fuction", "debug") - user = local.buffer["user"] + 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") # Проверить конфигурацию path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) path2 = "/usr/local/bin/mytoncore/mytoncore.db" if os.path.isfile(path) or os.path.isfile(path2): - local.AddLog("mytoncore.db already exist. Break FirstMytoncoreSettings fuction", "warning") + local.add_log("mytoncore.db already exist. Break FirstMytoncoreSettings fuction", "warning") return #end if @@ -372,47 +366,42 @@ def FirstMytoncoreSettings(): subprocess.run(args) # Подготовить папку mytoncore - mconfigPath = local.buffer["mconfigPath"] - mconfigDir = GetDirFromPath(mconfigPath) + mconfig_path = local.buffer.mconfig_path + mconfigDir = get_dir_from_path(mconfig_path) os.makedirs(mconfigDir, exist_ok=True) # create variables - srcDir = local.buffer["srcDir"] - tonBinDir = local.buffer["tonBinDir"] - tonSrcDir = local.buffer["tonSrcDir"] + src_dir = local.buffer.src_dir + ton_bin_dir = local.buffer.ton_bin_dir + ton_src_dir = local.buffer.ton_src_dir # general config - mconfig = dict() - mconfig["config"] = dict() - mconfig["config"]["logLevel"] = "debug" - mconfig["config"]["isLocaldbSaving"] = True + mconfig = Dict() + mconfig.config = Dict() + mconfig.config.logLevel = "debug" + mconfig.config.isLocaldbSaving = True # fift - fift = dict() - fift["appPath"] = tonBinDir + "crypto/fift" - fift["libsPath"] = tonSrcDir + "crypto/fift/lib" - fift["smartcontsPath"] = tonSrcDir + "crypto/smartcont" - mconfig["fift"] = fift + fift = Dict() + fift.appPath = ton_bin_dir + "crypto/fift" + fift.libsPath = ton_src_dir + "crypto/fift/lib" + fift.smartcontsPath = ton_src_dir + "crypto/smartcont" + mconfig.fift = fift # lite-client - liteClient = dict() - liteClient["appPath"] = tonBinDir + "lite-client/lite-client" - liteClient["configPath"] = tonBinDir + "global.config.json" - mconfig["liteClient"] = liteClient - - # miner - miner = dict() - miner["appPath"] = tonBinDir + "crypto/pow-miner" - mconfig["miner"] = miner + liteClient = Dict() + liteClient.appPath = ton_bin_dir + "lite-client/lite-client" + liteClient.configPath = ton_bin_dir + "global.config.json" + mconfig.liteClient = liteClient # Telemetry - mconfig["sendTelemetry"] = local.buffer["telemetry"] + mconfig.sendTelemetry = local.buffer.telemetry # Записать настройки в файл - SetConfig(path=mconfigPath, data=mconfig) + SetConfig(path=mconfig_path, data=mconfig) # chown 1 - args = ["chown", user + ':' + user, mconfigDir, mconfigPath] + args = ["chown", user + ':' + user, mconfigDir, mconfig_path] subprocess.run(args) # start mytoncore @@ -420,26 +409,26 @@ def FirstMytoncoreSettings(): #end define def EnableValidatorConsole(): - local.AddLog("start EnableValidatorConsole function", "debug") + local.add_log("start EnableValidatorConsole function", "debug") # Create variables - user = local.buffer["user"] - vuser = local.buffer["vuser"] - cport = local.buffer["cport"] - srcDir = local.buffer["srcDir"] - tonDbDir = local.buffer["tonDbDir"] - tonBinDir = local.buffer["tonBinDir"] - vconfigPath = local.buffer["vconfigPath"] - generate_random_id = tonBinDir + "utils/generate-random-id" - keysDir = local.buffer["keysDir"] - client_key = keysDir + "client" - server_key = keysDir + "server" + user = local.buffer.user + vuser = local.buffer.vuser + cport = local.buffer.cport + src_dir = local.buffer.src_dir + ton_db_dir = local.buffer.ton_db_dir + ton_bin_dir = local.buffer.ton_bin_dir + vconfig_path = local.buffer.vconfig_path + generate_random_id = ton_bin_dir + "utils/generate-random-id" + keys_dir = local.buffer.keys_dir + client_key = keys_dir + "client" + server_key = keys_dir + "server" client_pubkey = client_key + ".pub" server_pubkey = server_key + ".pub" # Check if key exist if os.path.isfile(server_key) or os.path.isfile(client_key): - local.AddLog("Server or client key already exist. Break EnableValidatorConsole fuction", "warning") + local.add_log("Server or client key already exist. Break EnableValidatorConsole fuction", "warning") return #end if @@ -452,7 +441,7 @@ def EnableValidatorConsole(): server_key_b64 = output_arr[1].replace('\n', '') # move key - newKeyPath = tonDbDir + "/keyring/" + server_key_hex + newKeyPath = ton_db_dir + "/keyring/" + server_key_hex args = ["mv", server_key, newKeyPath] subprocess.run(args) @@ -473,41 +462,41 @@ def EnableValidatorConsole(): subprocess.run(args) # read vconfig - vconfig = GetConfig(path=vconfigPath) + vconfig = GetConfig(path=vconfig_path) # prepare config - control = dict() - control["id"] = server_key_b64 - control["port"] = cport - allowed = dict() - allowed["id"] = client_key_b64 - allowed["permissions"] = 15 - control["allowed"] = [allowed] # fix me - vconfig["control"].append(control) + control = Dict() + control.id = server_key_b64 + control.port = cport + allowed = Dict() + allowed.id = client_key_b64 + allowed.permissions = 15 + control.allowed = [allowed] # fix me + vconfig.control.append(control) # write vconfig - SetConfig(path=vconfigPath, data=vconfig) + SetConfig(path=vconfig_path, data=vconfig) # restart validator StartValidator() # read mconfig - mconfigPath = local.buffer["mconfigPath"] - mconfig = GetConfig(path=mconfigPath) + mconfig_path = local.buffer.mconfig_path + mconfig = GetConfig(path=mconfig_path) # edit mytoncore config file - validatorConsole = dict() - validatorConsole["appPath"] = tonBinDir + "validator-engine-console/validator-engine-console" - validatorConsole["privKeyPath"] = client_key - validatorConsole["pubKeyPath"] = server_pubkey - validatorConsole["addr"] = "127.0.0.1:{cport}".format(cport=cport) - mconfig["validatorConsole"] = validatorConsole + validatorConsole = Dict() + validatorConsole.appPath = ton_bin_dir + "validator-engine-console/validator-engine-console" + validatorConsole.privKeyPath = client_key + validatorConsole.pubKeyPath = server_pubkey + validatorConsole.addr = "127.0.0.1:{cport}".format(cport=cport) + mconfig.validatorConsole = validatorConsole # write mconfig - SetConfig(path=mconfigPath, data=mconfig) + SetConfig(path=mconfig_path, data=mconfig) # Подтянуть событие в mytoncore.py - cmd = "python3 {srcDir}mytonctrl/mytoncore.py -e \"enableVC\"".format(srcDir=srcDir) + cmd = "python3 {src_dir}mytonctrl/mytoncore.py -e \"enableVC\"".format(src_dir=src_dir) args = ["su", "-l", user, "-c", cmd] subprocess.run(args) @@ -516,29 +505,29 @@ def EnableValidatorConsole(): #end define def EnableLiteServer(): - local.AddLog("start EnableLiteServer function", "debug") + local.add_log("start EnableLiteServer function", "debug") # Create variables - user = local.buffer["user"] - vuser = local.buffer["vuser"] - lport = local.buffer["lport"] - srcDir = local.buffer["srcDir"] - tonDbDir = local.buffer["tonDbDir"] - keysDir = local.buffer["keysDir"] - tonBinDir = local.buffer["tonBinDir"] - vconfigPath = local.buffer["vconfigPath"] - generate_random_id = tonBinDir + "utils/generate-random-id" - liteserver_key = keysDir + "liteserver" + user = local.buffer.user + vuser = local.buffer.vuser + lport = local.buffer.lport + src_dir = local.buffer.src_dir + ton_db_dir = local.buffer.ton_db_dir + keys_dir = local.buffer.keys_dir + ton_bin_dir = local.buffer.ton_bin_dir + vconfig_path = local.buffer.vconfig_path + generate_random_id = ton_bin_dir + "utils/generate-random-id" + liteserver_key = keys_dir + "liteserver" liteserver_pubkey = liteserver_key + ".pub" # Check if key exist if os.path.isfile(liteserver_pubkey): - local.AddLog("Liteserver key already exist. Break EnableLiteServer fuction", "warning") + local.add_log("Liteserver key already exist. Break EnableLiteServer fuction", "warning") return #end if # generate liteserver key - local.AddLog("generate liteserver key", "debug") + local.add_log("generate liteserver key", "debug") args = [generate_random_id, "--mode", "keys", "--name", liteserver_key] process = subprocess.run(args, stdout=subprocess.PIPE) output = process.stdout.decode("utf-8") @@ -547,56 +536,56 @@ def EnableLiteServer(): liteserver_key_b64 = output_arr[1].replace('\n', '') # move key - local.AddLog("move key", "debug") - newKeyPath = tonDbDir + "/keyring/" + liteserver_key_hex + local.add_log("move key", "debug") + newKeyPath = ton_db_dir + "/keyring/" + liteserver_key_hex args = ["mv", liteserver_key, newKeyPath] subprocess.run(args) # chown 1 - local.AddLog("chown 1", "debug") + local.add_log("chown 1", "debug") args = ["chown", vuser + ':' + vuser, newKeyPath] subprocess.run(args) # chown 2 - local.AddLog("chown 2", "debug") + local.add_log("chown 2", "debug") args = ["chown", user + ':' + user, liteserver_pubkey] subprocess.run(args) # read vconfig - local.AddLog("read vconfig", "debug") - vconfig = GetConfig(path=vconfigPath) + local.add_log("read vconfig", "debug") + vconfig = GetConfig(path=vconfig_path) # prepare vconfig - local.AddLog("prepare vconfig", "debug") - liteserver = dict() - liteserver["id"] = liteserver_key_b64 - liteserver["port"] = lport - vconfig["liteservers"].append(liteserver) + local.add_log("prepare vconfig", "debug") + liteserver = Dict() + liteserver.id = liteserver_key_b64 + liteserver.port = lport + vconfig.liteservers.append(liteserver) # write vconfig - local.AddLog("write vconfig", "debug") - SetConfig(path=vconfigPath, data=vconfig) + local.add_log("write vconfig", "debug") + SetConfig(path=vconfig_path, data=vconfig) # restart validator StartValidator() # edit mytoncore config file # read mconfig - local.AddLog("read mconfig", "debug") - mconfigPath = local.buffer["mconfigPath"] - mconfig = GetConfig(path=mconfigPath) + local.add_log("read mconfig", "debug") + mconfig_path = local.buffer.mconfig_path + mconfig = GetConfig(path=mconfig_path) # edit mytoncore config file - local.AddLog("edit mytoncore config file", "debug") - liteServer = dict() - liteServer["pubkeyPath"] = liteserver_pubkey - liteServer["ip"] = "127.0.0.1" - liteServer["port"] = lport - mconfig["liteClient"]["liteServer"] = liteServer + local.add_log("edit mytoncore config file", "debug") + liteServer = Dict() + liteServer.pubkeyPath = liteserver_pubkey + liteServer.ip = "127.0.0.1" + liteServer.port = lport + mconfig.liteClient.liteServer = liteServer # write mconfig - local.AddLog("write mconfig", "debug") - SetConfig(path=mconfigPath, data=mconfig) + local.add_log("write mconfig", "debug") + SetConfig(path=mconfig_path, data=mconfig) # restart mytoncore StartMytoncore() @@ -604,18 +593,18 @@ def EnableLiteServer(): def StartValidator(): # restart validator - local.AddLog("Start/restart validator service", "debug") + local.add_log("Start/restart validator service", "debug") args = ["systemctl", "restart", "validator"] subprocess.run(args) # sleep 10 sec - local.AddLog("sleep 10 sec", "debug") + local.add_log("sleep 10 sec", "debug") time.sleep(10) #end define def StartMytoncore(): # restart mytoncore - local.AddLog("Start/restart mytoncore service", "debug") + local.add_log("Start/restart mytoncore service", "debug") args = ["systemctl", "restart", "mytoncore"] subprocess.run(args) #end define @@ -625,7 +614,7 @@ def GetConfig(**kwargs): file = open(path, 'rt') text = file.read() file.close() - config = json.loads(text) + config = Dict(json.loads(text)) return config #end define @@ -641,48 +630,48 @@ def SetConfig(**kwargs): #end define def BackupVconfig(): - local.AddLog("Backup validator config file 'config.json' to 'config.json.backup'", "debug") - vconfigPath = local.buffer["vconfigPath"] - backupPath = vconfigPath + ".backup" - args = ["cp", vconfigPath, backupPath] + 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.AddLog("Backup mytoncore config file 'mytoncore.db' to 'mytoncore.db.backup'", "debug") - mconfigPath = local.buffer["mconfigPath"] - backupPath = mconfigPath + ".backup" - args = ["cp", mconfigPath, backupPath] + 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(): - vconfigPath = local.buffer["vconfigPath"] + vconfig_path = local.buffer.vconfig_path # read vconfig - local.AddLog("read vconfig", "debug") - vconfig = GetConfig(path=vconfigPath) + local.add_log("read vconfig", "debug") + vconfig = GetConfig(path=vconfig_path) # read mconfig - local.AddLog("read mconfig", "debug") - mconfigPath = local.buffer["mconfigPath"] - mconfig = GetConfig(path=mconfigPath) + local.add_log("read mconfig", "debug") + mconfig_path = local.buffer.mconfig_path + mconfig = GetConfig(path=mconfig_path) # edit mytoncore config file - local.AddLog("edit mytoncore config file", "debug") - mconfig["liteClient"]["liteServer"]["port"] = mconfig["liteservers"][0]["port"] - mconfig["validatorConsole"]["addr"] = "127.0.0.1:{}".format(mconfig["control"][0]["port"]) + 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.AddLog("write mconfig", "debug") - SetConfig(path=mconfigPath, data=mconfig) + local.add_log("write mconfig", "debug") + SetConfig(path=mconfig_path, data=mconfig) # restart mytoncore StartMytoncore() #end define def DangerousRecoveryValidatorConfigFile(): - local.AddLog("start DangerousRecoveryValidatorConfigFile function", "info") + local.add_log("start DangerousRecoveryValidatorConfigFile function", "info") # install and import cryptography library args = ["pip3", "install", "cryptography"] @@ -702,30 +691,30 @@ def DangerousRecoveryValidatorConfigFile(): #end for # Create config object - vconfig = dict() + vconfig = Dict() vconfig["@type"] = "engine.validator.config" - vconfig["out_port"] = 3278 + vconfig.out_port = 3278 # Create addrs object - buffer = dict() - buffer["@type"] = "engine.addr" - buffer["ip"] = ip2int(requests.get("https://ifconfig.me").text) - buffer["port"] = None - buffer["categories"] = [0, 1, 2, 3] - buffer["priority_categories"] = [] - vconfig["addrs"] = [buffer] + buff = Dict() + buff["@type"] = "engine.addr" + buff.ip = ip2int(get_own_ip()) + buff.port = None + buff.categories = [0, 1, 2, 3] + buff.priority_categories = [] + vconfig.addrs = [buff] # Get liteserver fragment - mconfigPath = local.buffer["mconfigPath"] - mconfig = GetConfig(path=mconfigPath) - lkey = mconfig["liteClient"]["liteServer"]["pubkeyPath"] - lport = mconfig["liteClient"]["liteServer"]["port"] + mconfig_path = local.buffer.mconfig_path + mconfig = GetConfig(path=mconfig_path) + lkey = mconfig.liteClient.liteServer.pubkeyPath + lport = mconfig.liteClient.liteServer.port # Read lite server pubkey file = open(lkey, 'rb') data = file.read() file.close() - lsPubkey = data[4:] + ls_pubkey = data[4:] # Search lite server priv key for item in keyring: @@ -737,21 +726,21 @@ def DangerousRecoveryValidatorConfigFile(): privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) pubkeyObject = privkeyObject.public_key() pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) - if pubkey == lsPubkey: - lsId = hex2b64(item) - keys.remove(lsId) + if pubkey == ls_pubkey: + ls_id = hex2b64(item) + keys.remove(ls_id) #end for # Create LS object - buffer = dict() - buffer["@type"] = "engine.liteServer" - buffer["id"] = lsId - buffer["port"] = lport - vconfig["liteservers"] = [buffer] + buff = Dict() + buff["@type"] = "engine.liteServer" + buff.id = ls_id + buff.port = lport + vconfig.liteservers = [buff] # Get validator-console fragment - ckey = mconfig["validatorConsole"]["pubKeyPath"] - addr = mconfig["validatorConsole"]["addr"] + ckey = mconfig.validatorConsole.pubKeyPath + addr = mconfig.validatorConsole.addr buff = addr.split(':') cport = int(buff[1]) @@ -777,16 +766,16 @@ def DangerousRecoveryValidatorConfigFile(): #end for # Create VC object - buffer = dict() - buffer2 = dict() - buffer["@type"] = "engine.controlInterface" - buffer["id"] = vcId - buffer["port"] = cport - buffer2["@type"] = "engine.controlProcess" - buffer2["id"] = None - buffer2["permissions"] = 15 - buffer["allowed"] = buffer2 - vconfig["control"] = [buffer] + buff = Dict() + buff2 = Dict() + buff["@type"] = "engine.controlInterface" + buff.id = vcId + buff.port = cport + buff2["@type"] = "engine.controlProcess" + buff2.id = None + buff2.permissions = 15 + buff.allowed = buff2 + vconfig.control = [buff] # Get dht fragment files = os.listdir("/var/ton-work/db") @@ -806,32 +795,32 @@ def DangerousRecoveryValidatorConfigFile(): #end for # Create dht object - buffer = dict() - buffer["@type"] = "engine.dht" - buffer["id"] = dhtId - vconfig["dht"] = [buffer] + buff = Dict() + buff["@type"] = "engine.dht" + buff.id = dhtId + vconfig.dht = [buff] # Create adnl object - adnl2 = dict() + adnl2 = Dict() adnl2["@type"] = "engine.adnl" - adnl2["id"] = dhtId - adnl2["category"] = 0 + adnl2.id = dhtId + adnl2.category = 0 # Create adnl object adnlId = hex2b64(mconfig["adnlAddr"]) keys.remove(adnlId) - adnl3 = dict() + adnl3 = Dict() adnl3["@type"] = "engine.adnl" - adnl3["id"] = adnlId - adnl3["category"] = 0 + adnl3.id = adnlId + adnl3.category = 0 # Create adnl object - adnl1 = dict() + adnl1 = Dict() adnl1["@type"] = "engine.adnl" - adnl1["id"] = keys.pop(0) - adnl1["category"] = 1 + adnl1.id = keys.pop(0) + adnl1.category = 1 - vconfig["adnl"] = [adnl1, adnl2, adnl3] + vconfig.adnl = [adnl1, adnl2, adnl3] # Get dumps from tmp dumps = list() @@ -855,23 +844,23 @@ def DangerousRecoveryValidatorConfigFile(): file.close() dump = json.loads(data) vkey = hex2b64(dump["validatorKey"]) - temp_key = dict() + temp_key = Dict() temp_key["@type"] = "engine.validatorTempKey" - temp_key["key"] = vkey - temp_key["expire_at"] = dump["endWorkTime"] - adnl_addr = dict() + temp_key.key = vkey + temp_key.expire_at = dump["endWorkTime"] + adnl_addr = Dict() adnl_addr["@type"] = "engine.validatorAdnlAddress" - adnl_addr["id"] = adnlId - adnl_addr["expire_at"] = dump["endWorkTime"] + adnl_addr.id = adnlId + adnl_addr.expire_at = dump["endWorkTime"] # Create validator object - validator = dict() + validator = Dict() validator["@type"] = "engine.validator" - validator["id"] = vkey - validator["temp_keys"] = [temp_key] - validator["adnl_addrs"] = [adnl_addr] - validator["election_date"] = dump["startWorkTime"] - validator["expire_at"] = dump["endWorkTime"] + validator.id = vkey + validator.temp_keys = [temp_key] + validator.adnl_addrs = [adnl_addr] + validator.election_date = dump["startWorkTime"] + validator.expire_at = dump["endWorkTime"] if vkey in keys: validators.append(validator) keys.remove(vkey) @@ -879,7 +868,7 @@ def DangerousRecoveryValidatorConfigFile(): #end while # Add validators object to vconfig - vconfig["validators"] = validators + vconfig.validators = validators print("vconfig:", json.dumps(vconfig, indent=4)) @@ -901,8 +890,8 @@ def b642hex(input): #end define def CreateSymlinks(): - local.AddLog("start CreateSymlinks fuction", "debug") - cport = local.buffer["cport"] + local.add_log("start CreateSymlinks fuction", "debug") + cport = local.buffer.cport mytonctrl_file = "/usr/bin/mytonctrl" fift_file = "/usr/bin/fift" @@ -937,18 +926,18 @@ def CreateSymlinks(): #end define def EnableDhtServer(): - local.AddLog("start EnableDhtServer function", "debug") - vuser = local.buffer["vuser"] - tonBinDir = local.buffer["tonBinDir"] - globalConfigPath = local.buffer["globalConfigPath"] - dht_server = tonBinDir + "dht-server/dht-server" - generate_random_id = tonBinDir + "utils/generate-random-id" + 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.AddLog("DHT-Server config.json already exist. Break EnableDhtServer fuction", "warning") + local.add_log("DHT-Server config.json already exist. Break EnableDhtServer fuction", "warning") return #end if @@ -958,10 +947,10 @@ def EnableDhtServer(): # Прописать автозагрузку 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) + add2systemd(name="dht-server", user=vuser, start=cmd) # Получить внешний ip адрес - ip = requests.get("https://ifconfig.me").text + ip = get_own_ip() port = random.randint(2000, 65000) addr = "{ip}:{port}".format(ip=ip, port=port) @@ -1000,26 +989,24 @@ def SetWebPassword(args): #end define def EnableJsonRpc(): - local.AddLog("start EnableJsonRpc function", "debug") - user = local.buffer["user"] - exitCode = RunAsRoot(["bash", "/usr/src/mytonctrl/scripts/jsonrpcinstaller.sh", "-u", user]) + 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}" - ColorPrint(text) + color_print(text) #end define def EnableTonHttpApi(): - local.AddLog("start EnableTonHttpApi function", "debug") - user = local.buffer["user"] - runArgs = ["bash", "/usr/src/mytonctrl/scripts/ton_http_api_installer.sh", "-u", user] - exitCode = RunAsRoot(runArgs) + local.add_log("start EnableTonHttpApi function", "debug") + exitCode = run_as_root(["bash", "/usr/src/mytonctrl/scripts/ton_http_api_installer.sh", "-u", local.buffer.user]) if exitCode == 0: text = "EnableTonHttpApi - {green}OK{endc}" else: text = "EnableTonHttpApi - {red}Error{endc}" - ColorPrint(text) + color_print(text) #end define def str2b64(s): @@ -1060,5 +1047,5 @@ def b642dict(b64): General() else: console.Run() - local.Exit() + local.exit() #end if diff --git a/translate.json b/translate.json index b5913621..60350335 100644 --- a/translate.json +++ b/translate.json @@ -1,326 +1,413 @@ { "update_cmd": { "en": "Pull mytonctrl update", - "ru": "Подтянуть обновление mytonctrl" + "ru": "Подтянуть обновление mytonctrl", + "zh_TW": "拉取 mytonctrl 更新" }, "upgrade_cmd": { "en": "Pull up the source code and recompile the TON components", - "ru": "Подтянуть исходный код и перекомпилировать компоненты TON" + "ru": "Подтянуть исходный код и перекомпилировать компоненты TON", + "zh_TW": "拉取源碼並重新編譯 TON 組件" }, "status_cmd": { "en": "Show TON status", - "ru": "Показать статус TON" + "ru": "Показать статус TON", + "zh_TW": "顯示 TON 狀態" }, "seqno_cmd": { "en": "Get seqno wallet", - "ru": "Получить seqno кошелька" + "ru": "Получить seqno кошелька", + "zh_TW": "取得 seqno 錢包" }, "getconfig_cmd": { "en": "Get config", - "ru": "Получить конфигурацию" + "ru": "Получить конфигурацию", + "zh_TW": "取得設定" }, "nw_cmd": { "en": "Create a new local wallet", - "ru": "Создать новый локальный кошелек" + "ru": "Создать новый локальный кошелек", + "zh_TW": "創建新的本地錢包" }, "aw_cmd": { "en": "Activate local wallet", - "ru": "Активировать локальный кошелек" + "ru": "Активировать локальный кошелек", + "zh_TW": "啟動本地錢包" }, "wl_cmd": { "en": "Show wallet list", - "ru": "Показать локальные кошельки" + "ru": "Показать локальные кошельки", + "zh_TW": "顯示錢包列表" }, "iw_cmd": { "en": "Import wallet", - "ru": "Импортировать кошелек" + "ru": "Импортировать кошелек", + "zh_TW": "匯入錢包" }, "swv_cmd": { "en": "Set wallet version", - "ru": "Установить версию кошелька" + "ru": "Установить версию кошелька", + "zh_TW": "設定錢包版本" }, "ex_cmd": { "en": "Export wallet", - "ru": "Экспортировать кошелек" + "ru": "Экспортировать кошелек", + "zh_TW": "匯出錢包" }, "swa_cmd": { "en": "Save wallet address to file", - "ru": "Сохранить адрес кошелька в файл" + "ru": "Сохранить адрес кошелька в файл", + "zh_TW": "將錢包地址儲存到檔案" }, "dw_cmd": { "en": "Delete local wallet", - "ru": "Удалить локальный кошелек" + "ru": "Удалить локальный кошелек", + "zh_TW": "刪除本地錢包" }, "vas_cmd": { "en": "View account status", - "ru": "Показать статус аккаунта" + "ru": "Показать статус аккаунта", + "zh_TW": "查看帳戶狀態" }, "vah_cmd": { "en": "View account history", - "ru": "Показать историю аккаунта" + "ru": "Показать историю аккаунта", + "zh_TW": "查看帳戶歷史" }, "mg_cmd": { "en": "Move coins to account", - "ru": "Перевод монет на кошелек" + "ru": "Перевод монет на кошелек", + "zh_TW": "將幣轉移到帳戶" }, "mgtp_cmd": { "en": "Move coins through proxy", - "ru": "Перевод монет через прокси" + "ru": "Перевод монет через прокси", + "zh_TW": "透過代理轉移幣" }, "nb_cmd": { "en": "Create new bookmark", - "ru": "Добавить аккаунт в закладки" + "ru": "Добавить аккаунт в закладки", + "zh_TW": "建立新的書籤" }, "bl_cmd": { "en": "Show bookmark list", - "ru": "Показать закладки" + "ru": "Показать закладки", + "zh_TW": "顯示書籤列表" }, "db_cmd": { "en": "Delete bookmark", - "ru": "Удалить закладку" + "ru": "Удалить закладку", + "zh_TW": "刪除書籤" }, "nd_cmd": { "en": "New domain", - "ru": "Арендовать новый домен" + "ru": "Арендовать новый домен", + "zh_TW": "新建域名" }, "dl_cmd": { "en": "Show domain list", - "ru": "Показать арендованные домены" + "ru": "Показать арендованные домены", + "zh_TW": "顯示域名列表" }, "vds_cmd": { "en": "View domain status", - "ru": "Показать статус домена" + "ru": "Показать статус домена", + "zh_TW": "查看域名狀態" }, "dd_cmd": { "en": "Delete domain", - "ru": "Удалить домен" + "ru": "Удалить домен", + "zh_TW": "刪除域名" }, "ol_cmd": { "en": "Show offers list", - "ru": "Показать действующие предложения" + "ru": "Показать действующие предложения", + "zh_TW": "顯示優惠列表" }, "vo_cmd": { "en": "Vote for offer", - "ru": "Голосовать за предложение" + "ru": "Голосовать за предложение", + "zh_TW": "投票支持優惠" }, "od_cmd": { "en": "Show offer diff", - "ru": "Показать разницу предложений" + "ru": "Показать разницу предложений", + "zh_TW": "顯示優惠差異" }, "cl_cmd": { "en": "Show complaints list", - "ru": "Показать действующие жалобы" + "ru": "Показать действующие жалобы", + "zh_TW": "顯示投訴列表" }, "vc_cmd": { "en": "Vote for complaint", - "ru": "Голосовать за жалобу" + "ru": "Голосовать за жалобу", + "zh_TW": "投票支持投訴" }, "el_cmd": { "en": "Show election entries list", - "ru": "Показать действующие выборы" + "ru": "Показать действующие выборы", + "zh_TW": "顯示選舉入口列表" }, "ve_cmd": { "en": "Vote election entry", - "ru": "Голосовать в выборах" + "ru": "Голосовать в выборах", + "zh_TW": "投票選舉入口" }, "vl_cmd": { "en": "Show active validators", - "ru": "Показать действующие валидаторы" + "ru": "Показать действующие валидаторы", + "zh_TW": "顯示活躍的驗證者" }, "get_cmd": { "en": "Get settings", - "ru": "Посмотреть настройки" + "ru": "Посмотреть настройки", + "zh_TW": "獲取設定" }, "set_cmd": { "en": "Set settings", - "ru": "Задать настройки" + "ru": "Задать настройки", + "zh_TW": "設定設定" }, "hr_cmd": { "en": "Get mining hashrate", - "ru": "Получить хешрейт сервера" + "ru": "Получить хешрейт сервера", + "zh_TW": "獲取挖礦哈希率" }, "mo_cmd": { "en": "Enable mining", - "ru": "Включить майнинг" + "ru": "Включить майнинг", + "zh_TW": "啟用挖礦" }, "moff_cmd": { "en": "Disable mining", - "ru": "Выключить майнинг" + "ru": "Выключить майнинг", + "zh_TW": "禁用挖礦" }, "installer_cmd": { "en": "Run the installer of TON modules", - "ru": "Запустить установщик модулей TON" + "ru": "Запустить установщик модулей TON", + "zh_TW": "執行 TON 模組的安裝程序" }, "ton_status_head": { "en": "{cyan}===[ TON network status ]==={endc}", - "ru": "{cyan}===[ Статус сети TON ]==={endc}" + "ru": "{cyan}===[ Статус сети TON ]==={endc}", + "zh_TW": "{cyan}===[ TON 網路狀態 ]==={endc}" }, "ton_status_tps": { "en": "Transactions per second (TPS): {0}, {1}, {2}", - "ru": "Транзакций в секунду (TPS): {0}, {1}, {2}" + "ru": "Транзакций в секунду (TPS): {0}, {1}, {2}", + "zh_TW": "每秒交易數 (TPS): {0}, {1}, {2}" }, "ton_status_validators": { "en": "Number of validators: {0}({1})", - "ru": "Количество валидаторов: {0}({1})" + "ru": "Количество валидаторов: {0}({1})", + "zh_TW": "驗證者數量: {0}({1})" }, "ton_status_shards": { "en": "Number of shardchains: {0}", - "ru": "Количесвто шардчейнов: {0}" + "ru": "Количесвто шардчейнов: {0}", + "zh_TW": "分片鏈數量: {0}" }, "ton_status_offers": { "en": "Number of offers: {0}({1})", - "ru": "Действующие предложения: {0}({1})" + "ru": "Действующие предложения: {0}({1})", + "zh_TW": "優惠數量: {0}({1})" }, "ton_status_complaints": { "en": "Number of complaints: {0}({1})", - "ru": "Действующие жалобы: {0}({1})" + "ru": "Действующие жалобы: {0}({1})", + "zh_TW": "投訴數量: {0}({1})" }, "ton_status_election": { "en": "Election status: {0}", - "ru": "Статус выборов: {0}" + "ru": "Статус выборов: {0}", + "zh_TW": "選舉狀態: {0}" }, "local_status_head": { "en": "{cyan}===[ Local validator status ]==={endc}", - "ru": "{cyan}===[ Статус локального валидатора ]==={endc}" + "ru": "{cyan}===[ Статус локального валидатора ]==={endc}", + "zh_TW": "{cyan}===[ 本地驗證者狀態 ]==={endc}" }, "local_status_validator_index": { "en": "Validator index: {0}", - "ru": "Индекс валидатора: {0}" + "ru": "Индекс валидатора: {0}", + "zh_TW": "驗證者索引: {0}" }, "local_status_validator_efficiency": { "en": "Validator efficiency: {0}", - "ru": "Эффективность валидатора: {0}" + "ru": "Эффективность валидатора: {0}", + "zh_TW": "驗證者效率: {0}" + }, + "local_status_validator_efficiency_ver2": { + "en": "Validator efficiency, ver.2: {0}", + "ru": "Эффективность валидатора, вер.2: {0}", + "zh_TW": "驗證器效率,版本2: {0}" }, "local_status_adnl_addr": { "en": "ADNL address of local validator: {0}", - "ru": "ADNL адрес локального валидатора: {0}" + "ru": "ADNL адрес локального валидатора: {0}", + "zh_TW": "本地驗證者的 ADNL 地址: {0}" }, "local_status_wallet_addr": { "en": "Local validator wallet address: {0}", - "ru": "Адрес кошелька локального валидатора: {0}" + "ru": "Адрес кошелька локального валидатора: {0}", + "zh_TW": "本地驗證者錢包地址: {0}" }, "local_status_wallet_balance": { "en": "Local validator wallet balance: {0}", - "ru": "Баланс кошелька локального валидатора: {0}" + "ru": "Баланс кошелька локального валидатора: {0}", + "zh_TW": "本地驗證者錢包餘額: {0}" }, "local_status_cpu_load": { "en": "Load average[{0}]: {1}, {2}, {3}", - "ru": "Средняя нагрузка[{0}]: {1}, {2}, {3}" + "ru": "Средняя нагрузка[{0}]: {1}, {2}, {3}", + "zh_TW": "平均負載[{0}]: {1}, {2}, {3}" }, "local_status_memory": { "en": "Memory load: {0}, {1}", - "ru": "Загрузка памяти: {0}, {1}" + "ru": "Загрузка памяти: {0}, {1}", + "zh_TW": "記憶體負載: {0}, {1}" }, "local_status_net_load": { "en": "Network load average (Mbit/s): {0}, {1}, {2}", - "ru": "Средняя нагрузка сети (Mbit/s): {0}, {1}, {2}" + "ru": "Средняя нагрузка сети (Mbit/s): {0}, {1}, {2}", + "zh_TW": "網絡平均負載 (Mbit/s): {0}, {1}, {2}" }, "local_status_disks_load": { "en": "Disks load average (MB/s): {0}", - "ru": "Средняя нагрузка дисков (MB/s): {0}" + "ru": "Средняя нагрузка дисков (MB/s): {0}", + "zh_TW": "磁碟平均負載 (MB/s): {0}" }, "local_status_mytoncore_status": { "en": "Mytoncore status: {0}, {1}", - "ru": "Статус ядра mytoncore: {0}, {1}" + "ru": "Статус ядра mytoncore: {0}, {1}", + "zh_TW": "Mytoncore 狀態: {0}, {1}" }, "local_status_validator_status": { "en": "Local validator status: {0}, {1}", - "ru": "Статус локального валидатора: {0}, {1}" + "ru": "Статус локального валидатора: {0}, {1}", + "zh_TW": "本地驗證者狀態: {0}, {1}" }, "local_status_validator_out_of_sync": { "en": "Local validator out of sync: {0}", - "ru": "Рассинхронизация локального валидатора: {0}" + "ru": "Рассинхронизация локального валидатора: {0}", + "zh_TW": "本地驗證者不同步: {0}" }, "local_status_db": { "en": "Local validator database size: {0}, {1}", - "ru": "Размер БД локального валидатора: {0}, {1}" + "ru": "Размер БД локального валидатора: {0}, {1}", + "zh_TW": "本地驗證者數據庫大小: {0}, {1}" }, "local_status_version_mtc": { "en": "Version mytonctrl: {0} ({1})", - "ru": "Версия mytonctrl: {0} ({1})" + "ru": "Версия mytonctrl: {0} ({1})", + "zh_TW": "mytonctrl 版本: {0} ({1})" }, "local_status_version_validator": { "en": "Version validator: {0} ({1})", - "ru": "Версия валидатора: {0} ({1})" + "ru": "Версия валидатора: {0} ({1})", + "zh_TW": "驗證者版本: {0} ({1})" }, "ton_config_head": { "en": "{cyan}===[ TON network configuration ]==={endc}", - "ru": "{cyan}===[ Конфигурация сети TON ]==={endc}" + "ru": "{cyan}===[ Конфигурация сети TON ]==={endc}", + "zh_TW": "{cyan}===[ TON 網絡配置 ]==={endc}" }, "ton_config_configurator_addr": { "en": "Configurator address: {0}", - "ru": "Адрес конфигуратора: {0}" + "ru": "Адрес конфигуратора: {0}", + "zh_TW": "配置器地址: {0}" }, "ton_config_elector_addr": { "en": "Elector address: {0}", - "ru": "Адрес электора: {0}" + "ru": "Адрес электора: {0}", + "zh_TW": "選舉人地址: {0}" }, "ton_config_elections": { "en": "Validation period: {0}, Duration of elections: {1}-{2}, Hold period: {3}", - "ru": "Период валидации: {0}, Длительность выборов: {1}-{2}, Период удержания ставки: {3}" + "ru": "Период валидации: {0}, Длительность выборов: {1}-{2}, Период удержания ставки: {3}", + "zh_TW": "驗證期間: {0}, 選舉期間: {1}-{2}, 持有期間: {3}" }, "ton_config_stake": { "en": "Minimum stake: {0}, Maximum stake: {1}", - "ru": "Минимальная ставка: {0}, Максимальная ставка: {1}" + "ru": "Минимальная ставка: {0}, Максимальная ставка: {1}", + "zh_TW": "最小賭注: {0}, 最大賭注: {1}" }, "times_head": { "en": "{cyan}===[ TON timestamps ]==={endc}", - "ru": "{cyan}===[ Временные метки TON ]==={endc}" + "ru": "{cyan}===[ Временные метки TON ]==={endc}", + "zh_TW": "{cyan}===[ TON 時間戳 ]==={endc}" }, "times_root_workchain_enabled_time": { "en": "TON network was launched: {0}", - "ru": "TON сеть была запущена: {0}" + "ru": "TON сеть была запущена: {0}", + "zh_TW": "TON 網絡啟動時間: {0}" }, "times_start_validation_time": { "en": "Start of the validation cycle: {0}", - "ru": "Начало цикла валидации: {0}" + "ru": "Начало цикла валидации: {0}", + "zh_TW": "驗證週期開始: {0}" }, "times_end_validation_time": { "en": "End of the validation cycle: {0}", - "ru": "Конец цикла валидации: {0}" + "ru": "Конец цикла валидации: {0}", + "zh_TW": "驗證週期結束: {0}" }, "times_start_election_time": { "en": "Start of elections: {0}", - "ru": "Начало выборов: {0}" + "ru": "Начало выборов: {0}", + "zh_TW": "選舉開始: {0}" }, "times_end_election_time": { "en": "End of elections: {0}", - "ru": "Конец выборов: {0}" + "ru": "Конец выборов: {0}", + "zh_TW": "選舉結束: {0}" }, "times_start_next_election_time": { "en": "Beginning of the next elections: {0}", - "ru": "Начало следующих выборов: {0}" + "ru": "Начало следующих выборов: {0}", + "zh_TW": "下一次選舉開始: {0}" }, "mytonctrl_update_available": { "en": "{green}MyTonCtrl update available. {red}Please update it with `update` command.{endc}", - "ru": "{green}Доступно обновление MyTonCtrl. {red}Пожалуйста, обновите его с помощью команды `update`.{endc}" + "ru": "{green}Доступно обновление MyTonCtrl. {red}Пожалуйста, обновите его с помощью команды `update`.{endc}", + "zh_TW": "{green}MyTonCtrl 有可用更新. {red}請使用 `update` 命令進行更新.{endc}" }, "ton_update_available": { "en": "{green}TON update available. {red}Please update it with `upgrade` command.{endc}", - "ru": "{green}Доступно обновление TON. {red}Пожалуйста, обновите его с помощью команды `upgrade`.{endc}" + "ru": "{green}Доступно обновление TON. {red}Пожалуйста, обновите его с помощью команды `upgrade`.{endc}", + "zh_TW": "{green}TON 有可用更新. {red}請使用 `upgrade` 命令進行更新.{endc}" }, - "test": { - "en": "001", - "ru": "002" + "vport_error": { + "en": "{red}Error - UDP port of the validator is not accessible from the outside.{endc}", + "ru": "{red}Ошибка - UDP порт валидатора недоступен извне.{endc}", + "zh_TW": "{red}錯誤 - 驗證器的 UDP 端口無法從外部訪問.{endc}" }, - "000": { + "000a": { "en": "001", - "ru": "002" + "ru": "002", + "zh_TW": "003" }, - "000": { + "000b": { "en": "001", - "ru": "002" + "ru": "002", + "zh_TW": "003" }, - "000": { + "000c": { "en": "001", - "ru": "002" + "ru": "002", + "zh_TW": "003" }, - "000": { + "000d": { "en": "001", - "ru": "002" + "ru": "002", + "zh_TW": "003" }, - "000": { + "000e": { "en": "001", - "ru": "002" + "ru": "002", + "zh_TW": "003" } + } From 25df7de3fd49796a6cf8d7942dbc16cfd7c49715 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:37:57 +0300 Subject: [PATCH 031/236] Create session_stats.py --- functions/session_stats.py | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 functions/session_stats.py diff --git a/functions/session_stats.py b/functions/session_stats.py new file mode 100644 index 00000000..ba08b06e --- /dev/null +++ b/functions/session_stats.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# -*- coding: utf_8 -*- + +import os +import sys +import time +import json +sys.path.append("/usr/src/mytonctrl/") +from mypylib.mypylib import Dict + +def read_session_stats(need_time_period): + #print(f"read_session_stats: {need_time_period}") + file_path = "/var/ton-work/log.session-stats" + average_block_time = calculate_average_block_time(file_path) + need_blocks = int(need_time_period/average_block_time) + + lines = read_last_lines(file_path, need_lines=need_blocks) + #lines = read_all_lines(file_path) + data = lines2data(lines) + + result = Dict() + result.my_blocks = 0 + result.my_need_blocks = 0 + result.all_master_blocks = 0 + result.all_blocks = len(data) + for buff in data: + if buff.id.workchain == -1: + result.all_master_blocks += 1 + first_producer = buff.rounds[0].producers[0] + if buff.self != first_producer.id: + continue + result.my_need_blocks += 1 + if buff.self == buff.creator: + result.my_blocks += 1 + #end for + return result +#end define + +def calculate_average_block_time(file_path): + blocks = 100 + lines = read_last_lines(file_path, need_lines=blocks) + data = lines2data(lines) + first_block, last_block = get_first_last_block(data) + + diff = int(last_block.timestamp) - int(first_block.timestamp) + average_block_time = round(diff/blocks, 2) + #print("average_block_time:", average_block_time) + return average_block_time +#end define + +def get_first_last_block(data, last_index=-1): + first_block = data[0] + last_block = data[last_index] + if first_block.id.workchain == last_block.id.workchain: + blocks = int(last_block.id.seqno) - int(first_block.id.seqno) + else: + first_block, last_block = get_first_last_block(data, last_index=last_index-1) + return first_block, last_block +#end define + +def lines2data(lines): + #start = time.time() + data = list() + for line in lines: + try: + buff = json.loads(line) + data.append(Dict(buff)) + except json.decoder.JSONDecodeError: + pass + #end for + + #end = time.time() + #diff = round(end - start, 2) + #print(f"lines2data completed in {diff} seconds") + return data +#end define + +def read_all_lines(file_path): + #start = time.time() + with open(file_path, 'rt') as file: + text = file.read() + #end with + lines = text.split('\n') + + #end = time.time() + #diff = round(end - start, 2) + #print(f"read_all_lines completed in {diff} seconds") + return lines +#end define + +def read_last_lines(file_path, need_lines): + lines = list() + max_lines = 30000 + if need_lines < 1: + return lines + elif need_lines > max_lines: + need_lines = max_lines + #print(f"read_last_lines: {need_lines}") + #start = time.time() + with open(file_path, 'rb') as file: + find_last_lines(file, need_lines) + for i in range(need_lines): + line = file.readline().decode() + lines.append(line) + #end with + + + #end = time.time() + #diff = round(end - start, 2) + #print(f"read_last_lines {len(lines)} completed in {diff} seconds") + return lines +#end define + +def find_last_lines(file, need_lines): + # catch OSError in case of a one line file + try: + find_lines = 0 + #file.seek(-2, os.SEEK_END) + #while find_lines != need_lines: + # if file.read(1) == b'\n': + # find_lines += 1 + # file.seek(-2, os.SEEK_CUR) + + file.seek(-100, os.SEEK_END) + while find_lines != need_lines: + if b'\n' in file.read(100): + find_lines += 1 + file.seek(-200, os.SEEK_CUR) + except OSError: + file.seek(0) +#end define + + + + + From f2ece1063e74472ae838c0c6b4ed90ead6a8f83a Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:40:53 +0300 Subject: [PATCH 032/236] Update mytoncore.py --- mytoncore.py | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/mytoncore.py b/mytoncore.py index 3a782973..58de8b6b 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3677,7 +3677,7 @@ def CreateControllers(self): return #end if - local.AddLog("start CreateControllers function", "debug") + local.add_log("start CreateControllers function", "debug") wallet = self.GetValidatorWallet() liquid_pool_addr = self.GetLiquidPoolAddr() contractPath = self.contractsDir + "jetton_pool/" @@ -3696,7 +3696,7 @@ def CreateControllers(self): # Сохранить новые контроллеры local.db["old_controllers"] = old_controllers local.db["using_controllers"] = new_controllers - local.dbSave() + local.save() #end define def GetControllerAddress(self, controller_id): @@ -3714,7 +3714,7 @@ def GetControllerAddress(self, controller_id): #end define def CheckController(self, controllerAddr): - local.AddLog("start CheckController function", "debug") + local.add_log("start CheckController function", "debug") controllerData = self.GetControllerData(controllerAddr) using_controllers = local.db.get("using_controllers", list()) if controllerData is None: @@ -3726,7 +3726,7 @@ def CheckController(self, controllerAddr): #end define def GetControllers(self): - local.AddLog("start GetControllers function", "debug") + local.add_log("start GetControllers function", "debug") controller0 = self.GetControllerAddress(controller_id=0) controller1 = self.GetControllerAddress(controller_id=1) controllers = [controller0, controller1] @@ -3790,7 +3790,7 @@ def GetControllerData(self, controllerAddr): #end define def CreateLoanRequest(self, controllerAddr): - local.AddLog("start CreateLoanRequest function", "debug") + local.add_log("start CreateLoanRequest function", "debug") min_loan = local.db.get("min_loan", 41000) max_loan = local.db.get("max_loan", 43000) max_interest_percent = local.db.get("max_interest_percent", 1.5) @@ -3799,7 +3799,7 @@ def CreateLoanRequest(self, controllerAddr): # Проверить наличие действующего кредита controllerData = self.GetControllerData(controllerAddr) if controllerData["borrowed_amount"] > 0: - local.AddLog("CreateLoanRequest warning: past loan found", "warning") + local.add_log("CreateLoanRequest warning: past loan found", "warning") return #end define @@ -3845,7 +3845,7 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): #end define def WaitLoan(self, controllerAddr): - local.AddLog("start WaitLoan function", "debug") + local.add_log("start WaitLoan function", "debug") for i in range(10): time.sleep(3) controllerData = self.GetControllerData(controllerAddr) @@ -3855,7 +3855,7 @@ def WaitLoan(self, controllerAddr): #end define def ReturnUnusedLoan(self, controllerAddr): - local.AddLog("start ReturnUnusedLoan function", "debug") + local.add_log("start ReturnUnusedLoan function", "debug") wallet = self.GetValidatorWallet() fileName = self.contractsDir + "jetton_pool/fift-scripts/return_unused_loan.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.05) @@ -3863,7 +3863,7 @@ def ReturnUnusedLoan(self, controllerAddr): #end define def DepositToController(self, controllerAddr, amount): - local.AddLog("start DepositToController function", "debug") + local.add_log("start DepositToController function", "debug") wallet = self.GetValidatorWallet() fileName = self.contractsDir + "jetton_pool/fift-scripts/top-up.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, amount) @@ -3886,7 +3886,7 @@ def WithdrawFromControllerProcess(self, controllerAddr, amount): return #end if - local.AddLog("start WithdrawFromControllerProcess function", "debug") + local.add_log("start WithdrawFromControllerProcess function", "debug") wallet = self.GetValidatorWallet() fiftScript = self.contractsDir + "jetton_pool/fift-scripts/withdraw-controller.fif" resultFilePath = self.tempDir + self.nodeName + wallet.name + "_withdraw_request.boc" @@ -3897,10 +3897,10 @@ def WithdrawFromControllerProcess(self, controllerAddr, amount): #end define def PendWithdrawFromController(self, controllerAddr, amount): - local.AddLog("start PendWithdrawFromController function", "debug") + local.add_log("start PendWithdrawFromController function", "debug") controllerPendingWithdraws = self.GetControllerPendingWithdraws() controllerPendingWithdraws[controllerAddr] = amount - local.dbSave() + local.save() #end define def HandleControllerPendingWithdraw(self, controllerPendingWithdraws, controllerAddr): @@ -3919,20 +3919,20 @@ def GetControllerPendingWithdraws(self): #end define def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): - local.AddLog("start SignElectionRequestWithController function", "debug") + local.add_log("start SignElectionRequestWithController function", "debug") fileName = self.tempDir + str(startWorkTime) + "_validator-query.boc" fiftScript = self.contractsDir + "jetton_pool/fift-scripts/controller-elect-signed.fif" args = [fiftScript, controllerAddr, startWorkTime, maxFactor, adnlAddr, validatorPubkey_b64, validatorSignature, fileName, stake] - local.AddLog(f"SignElectionRequestWithController args: {args}", "debug") + local.add_log(f"SignElectionRequestWithController args: {args}", "debug") result = self.fift.Run(args) - local.AddLog(f"SignElectionRequestWithController result: {result}", "debug") + local.add_log(f"SignElectionRequestWithController result: {result}", "debug") pubkey = Pars(result, "validator public key ", '\n') fileName = Pars(result, "Saved to file ", '\n') return pubkey, fileName #end define def ControllersUpdateValidatorSet(self): - local.AddLog("start ControllersUpdateValidatorSet function", "debug") + local.add_log("start ControllersUpdateValidatorSet function", "debug") using_controllers = local.db.get("using_controllers") user_controllers = local.db.get("user_controllers", list()) old_controllers = local.db.get("old_controllers", list()) @@ -3941,7 +3941,7 @@ def ControllersUpdateValidatorSet(self): #end define def ControllerUpdateValidatorSet(self, controllerAddr): - local.AddLog("start ControllerUpdateValidatorSet function", "debug") + local.add_log("start ControllerUpdateValidatorSet function", "debug") wallet = self.GetValidatorWallet() controllers = self.GetControllers() controllerData = self.GetControllerData(controllerAddr) @@ -3976,20 +3976,20 @@ def ControllerUpdateValidatorSet(self, controllerAddr): #end define def ControllerUpdateValidatorSetProcess(self, controllerAddr, wallet): - local.AddLog("start ControllerUpdateValidatorSetProcess function", "debug") + local.add_log("start ControllerUpdateValidatorSetProcess function", "debug") fileName = self.contractsDir + "jetton_pool/fift-scripts/update_validator_hash.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.07) self.SendFile(resultFilePath, wallet) - local.AddLog("ControllerUpdateValidatorSetProcess completed") + local.add_log("ControllerUpdateValidatorSetProcess completed") #end define def ControllerRecoverStake(self, controllerAddr): wallet = self.GetValidatorWallet() - local.AddLog("start ControllerRecoverStake function", "debug") + local.add_log("start ControllerRecoverStake function", "debug") fileName = self.contractsDir + "jetton_pool/fift-scripts/recover_stake.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.04) self.SendFile(resultFilePath, wallet) - local.AddLog("ControllerRecoverStake completed") + local.add_log("ControllerRecoverStake completed") #end define def StopController(self, controllerAddr): @@ -4003,7 +4003,7 @@ def StopController(self, controllerAddr): user_controllers = local.db.get("user_controllers") if user_controllers is not None and controllerAddr in user_controllers: user_controllers.remove(controllerAddr) - local.dbSave() + local.save() #end define def AddController(self, controllerAddr): @@ -4017,7 +4017,7 @@ def AddController(self, controllerAddr): stop_controllers_list = local.db.get("stop_controllers_list") if stop_controllers_list is not None and controllerAddr in stop_controllers_list: stop_controllers_list.remove(controllerAddr) - local.dbSave() + local.save() #end define def CheckLiquidPool(self): From 351c15d1c4765593117caf3ab0635d03a3834677 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 14 Sep 2023 20:42:15 +0300 Subject: [PATCH 033/236] Update mytonctrl.py --- mytonctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl.py b/mytonctrl.py index 36267433..19f2fc2e 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -1264,7 +1264,7 @@ def PrintControllersListProcess(controllers): approved = True if controllerData and controllerData["approved"] == -1 else False state = controllerData["state"] if controllerData else None table += [[controllerAddr, account.status, account.balance, approved, state]] - PrintTable(table) + print_table(table) #end define def GetControllerData(args): From e995600ebd243b05e3f8ccfa2e3eac9972809f5b Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 14 Sep 2023 22:05:26 +0300 Subject: [PATCH 034/236] Update mytonctrl.py --- mytonctrl.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/mytonctrl.py b/mytonctrl.py index 19f2fc2e..87c47567 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -1231,7 +1231,7 @@ def PoolUpdateValidatorSet(args): def CreateControllers(args): ton.CreateControllers() - ColorPrint("CreateControllers - {green}OK{endc}") + color_print("CreateControllers - {green}OK{endc}") #end define def PrintControllersList(args): @@ -1271,7 +1271,7 @@ def GetControllerData(args): try: controllerAddr = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} get_controller_data ") + color_print("{red}Bad args. Usage:{endc} get_controller_data ") return controllerData = ton.GetControllerData(controllerAddr) print(json.dumps(controllerData, indent=4)) @@ -1282,7 +1282,7 @@ def DepositToController(args): controllerAddr = args[0] amount = float(args[1]) except: - ColorPrint("{red}Bad args. Usage:{endc} deposit_to_controller ") + color_print("{red}Bad args. Usage:{endc} deposit_to_controller ") return ton.DepositToController(controllerAddr, amount) #end define @@ -1292,7 +1292,7 @@ def WithdrawFromController(args): controllerAddr = args[0] amount = GetItemFromList(args, 1) except: - ColorPrint("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") + color_print("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") return ton.WithdrawFromController(controllerAddr, amount) #end define @@ -1318,20 +1318,20 @@ def ControllerUpdateValidatorSet(args): try: controllerAddr = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} controller_update_validator_set ") + color_print("{red}Bad args. Usage:{endc} controller_update_validator_set ") return ton.ControllerUpdateValidatorSet(controllerAddr) - ColorPrint("ControllerUpdateValidatorSet - {green}OK{endc}") + color_print("ControllerUpdateValidatorSet - {green}OK{endc}") #end define def StopController(args): try: controllerAddr = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} stop_controller ") + color_print("{red}Bad args. Usage:{endc} stop_controller ") return ton.StopController(controllerAddr) - ColorPrint("StopController - {green}OK{endc}") + color_print("StopController - {green}OK{endc}") #end define def StopAndWithdrawController(args): @@ -1339,29 +1339,29 @@ def StopAndWithdrawController(args): controllerAddr = args[0] amount = GetItemFromList(args, 1) except: - ColorPrint("{red}Bad args. Usage:{endc} stop_and_withdraw_controller [amount]") + color_print("{red}Bad args. Usage:{endc} stop_and_withdraw_controller [amount]") return if amount is None: account = ton.GetAccount(controllerAddr) amount = account.balance-10.1 ton.StopController(controllerAddr) ton.WithdrawFromController(controllerAddr, amount) - ColorPrint("StopAndWithdrawController - {green}OK{endc}") + color_print("StopAndWithdrawController - {green}OK{endc}") #end define def AddController(args): try: controllerAddr = args[0] except: - ColorPrint("{red}Bad args. Usage:{endc} add_controller ") + color_print("{red}Bad args. Usage:{endc} add_controller ") return ton.AddController(controllerAddr) - ColorPrint("AddController - {green}OK{endc}") + color_print("AddController - {green}OK{endc}") #end define def CheckLiquidPool(args): ton.CheckLiquidPool() - ColorPrint("CheckLiquidPool - {green}OK{endc}") + color_print("CheckLiquidPool - {green}OK{endc}") #end define From 1ba23fb47436b81f5531eceeebdca8ad7db97984 Mon Sep 17 00:00:00 2001 From: kdimentionaltree Date: Fri, 26 Aug 2022 12:09:37 +0200 Subject: [PATCH 035/236] Gigacommit with refactoring WIP Refactor of logic Refractoring of mytoninstaller.py Fixed inject_globals Removed print Fixed typos WIP WIP WIP WIP WIP2 WIP RC Fix Fixed scripts Crc16 -> fastcrc tonhttpapi installer Fixed merge WIP Split on three modules, added mypylib and mypyconsole submodules Added imports in mytoncore Updated mtc-jsonrpc installer update mtc-jsonrpc installer WIP Try fix merge conflicts Rebase. New commits apply 1. a61ab21 - add ubuntu 22.04 to the list of tested OS 2. a41ad04 - Update README.Ru.md 3. b12f234 - Add Traditional Chinese Support and Fix JSON Format Errors 4. d152a70 - Update README with tested operating systems and installation scripts 5. 329c6bd - Refactor wallet import documentation 6. 5d6afcd - feat: Add import wallet documentation 7. d00a94a - Refactor: Rename FAQ files to markdown format 8. e417285 - Add import-wallets.md file for importing wallets with private keys or mnemonic phrases. 9. 17b45b1 - Refactor directory usage and add error handling 10. 2458f8b - Add FAQ.md with instructions on how to install, remove and configure MyTonCtrl 11. 3748e9c - Refactor MyTonCtrl directory usage 12. dd5825d - Add instructions for using mytonctrl on Ubuntu 13. 559480d - Refactor installation instructions and add operability test 14. 4e41c94 - Refactor installation instructions for mytonctrl on Ubuntu 15. a9df737 - Refactor pool activation and deposit instructions 16. 4fb4a0f - Add Chinese translation for Nominator Pool documentation. 17. 47ad5cf - feat: Add instructions for running a validator node in nominator pool mode 18. c36fa7f - Refactor documentation for running a validator in nominator pool 19. b9c068f - Refactor Nominator Pool documentation for clarity 20. 95f6823 - Refactor README.md to include more detailed information 21. e52aa1c - Merge branch 'master' into update-documentation 22. f03095f - Add badges and fix formatting in README 22. cc711df - Refactor documentation structure and add MyTonCtrl installer mode 23. 4294fa8 - Refactor commit message: 24. 9d25122 - Update FAQ.md with improved formatting and content 25. 6f759c1 - Update Chinese translation of nominator-pool.md 26. 8c17c60 - Add stake param setting for nominator pool docs 27. 776cde0 - Fix tabs 28. 456b2dc - Merge remote-tracking branch 'sonofmom/feature/update_docs' into update-documentation 29. 9a993a7 - Add null stake option to usePool command 30. 2556501 - upgrade with ninja 31. ec3a8b9 - persist global.config.json before the upgrade 32. d51d20e - make persistence of global.config.json rights friendly 33. b3bc22e - clean up build directory (without removing it) prior to upgrade 34. 953e991 - avoid usage of /tmp dir on clean up 35. 8e14dec - Merge pull request #127 from Gusarich/master 36. e5978dd - Merge pull request #128 from awesome-doge/add-traditional-chinese-support 37. 4e97349 - Merge pull request #129 from awesome-doge/update-documentation 38. c1eee8d - Merge pull request #131 from neodiX42/upgrade-with-ninja 39. Applying commit efbf35c "update mypylib" Replay commit ef7d665 "bugfix" Replay commit 8733452 "upgrade bugfix" Replay commit 2a359a8 "update mypylib" Replay commits: 1. f1f5247 - add GetDomainFromAuction function 2. ac0d138 - Merge pull request #135 from ton-blockchain/master 3. 17fd02c - Merge pull request #136 from ton-blockchain/dev Replay commit dc56e83 "get_service_uptime bugfix on systems without systemd" Replay commits: 1. c3f3119 - mytoninstaller.py bugfix 2. 2c68e2f - bugfix if the files are in the wrong place Replay commit c789ebc "bugfix and moving to PEP8 stile" Replay commit 857b5a5 "bugfix" Replay commit 966f1a7 "bugfix" and update install.sh Refactor installation instructions for mytonctrl on Ubuntu The commit refactors the installation instructions for mytonctrl on Ubuntu. The changes include updating the language, adding numbered steps, and clarifying commands. Additionally, the commit adds a section to check wallet balances and activate wallets. Finally, it includes information about checking logs and using help commands. Refactor documentation for running a validator in nominator pool The commit message summarizes the changes made to the documentation for running a validator in a nominator pool. The changes include updating instructions on hardware requirements, recommended providers, and steps for creating and activating pools. Additionally, the commit includes instructions for switching from an individual validator to a nominator pool. Refactor Nominator Pool documentation for clarity This commit refactors the Nominator Pool documentation to improve its readability and clarity. Changes include rewording sentences, adding hyperlinks, and providing additional explanations for certain steps. The commit also includes a section on transitioning a regular validator to nominator pool mode. Refactor README.md to include more detailed information This commit refactors the README.md file to include a table of contents, installation instructions, and useful links. It also adds documentation in English, Russian, and Mandarin for frequently asked questions, importing wallets, manuals for Ubuntu, and nominator pools. Additionally, it includes information on telemetry and a web admin panel. Refactor documentation structure and add MyTonCtrl installer mode This commit refactors the documentation structure for MyTonCtrl, categorizing technical documents by language. It also adds a new feature, MyTonCtrl installer mode, which includes a web admin panel and local copy of toncenter. The web admin panel allows users to control the node/validator through their browser after installing an additional module. A local copy of toncenter can be set up on the user's server by enabling another module in the installer. add GetDomainFromAuction function Fix duplicated method GetDomainFromAuction --- .gitignore | 120 ++ .gitmodules | 4 +- README.Ru.md => README.RU.md | 0 README.md | 2 +- docs/en/FAQ.md | 2 +- docs/en/import-wallets.md | 5 +- docs/en/nominator-pool.md | 2 +- docs/ru/FAQ.md | 2 +- docs/ru/import-wallets.md | 4 +- docs/ru/nominator-pool.md | 2 +- docs/zh_TW/FAQ.md | 2 +- docs/zh_TW/import-wallets.md | 2 +- docs/zh_TW/manual-ubuntu.md | 2 +- docs/zh_TW/nominator-pool.md | 2 +- mytoncore/__init__.py | 4 + mytoncore/__main__.py | 5 + mytoncore/fift.py | 27 + mytoncore/functions.py | 585 +++++++ mytoncore/liteclient.py | 44 + mytoncore/models.py | 177 ++ mytoncore.py => mytoncore/mytoncore.py | 1418 +++++------------ mytoncore/tonblocksscanner.py | 208 +++ mytoncore/utils.py | 79 + mytoncore/validator_console.py | 27 + mytonctrl/__init__.py | 0 mytonctrl/__main__.py | 4 + mytonctrl.py => mytonctrl/mytonctrl.py | 576 +++++-- .../resources/translate.json | 0 {scripts => mytonctrl/scripts}/update.sh | 16 +- {scripts => mytonctrl/scripts}/upgrade.sh | 4 + {scripts => mytonctrl/scripts}/xrestart.py | 2 +- mytoninstaller/__init__.py | 0 mytoninstaller/__main__.py | 5 + mytoninstaller/config.py | 136 ++ mytoninstaller/mytoninstaller.py | 239 +++ mytoninstaller/scripts/__init__.py | 0 mytoninstaller/scripts/add2systemd.sh | 62 + .../scripts}/jsonrpcinstaller.sh | 16 +- .../scripts}/pytonv3installer.sh | 5 +- mytoninstaller/scripts/tonhttpapiinstaller.sh | 38 + .../settings.py | 610 ++----- mytoninstaller/utils.py | 33 + requirements.txt | 5 + scripts/install.sh | 98 +- scripts/{toninstaller.sh => ton_installer.sh} | 82 +- scripts/uninstall.sh | 33 +- scripts/upgrade.py | 31 - setup.py | 43 + tests/__init__.py | 0 tests/blocksScanner.py | 7 +- tests/bounce.py | 27 +- tests/mg.py | 4 +- tests/tpsLoad.py | 35 +- tests/tpsLoad2.py | 34 +- 54 files changed, 2975 insertions(+), 1895 deletions(-) rename README.Ru.md => README.RU.md (100%) create mode 100644 mytoncore/__init__.py create mode 100644 mytoncore/__main__.py create mode 100644 mytoncore/fift.py create mode 100755 mytoncore/functions.py create mode 100644 mytoncore/liteclient.py create mode 100644 mytoncore/models.py rename mytoncore.py => mytoncore/mytoncore.py (75%) mode change 100755 => 100644 create mode 100644 mytoncore/tonblocksscanner.py create mode 100644 mytoncore/utils.py create mode 100644 mytoncore/validator_console.py create mode 100644 mytonctrl/__init__.py create mode 100644 mytonctrl/__main__.py rename mytonctrl.py => mytonctrl/mytonctrl.py (69%) rename translate.json => mytonctrl/resources/translate.json (100%) rename {scripts => mytonctrl/scripts}/update.sh (73%) rename {scripts => mytonctrl/scripts}/upgrade.sh (93%) rename {scripts => mytonctrl/scripts}/xrestart.py (99%) create mode 100644 mytoninstaller/__init__.py create mode 100644 mytoninstaller/__main__.py create mode 100644 mytoninstaller/config.py create mode 100644 mytoninstaller/mytoninstaller.py create mode 100644 mytoninstaller/scripts/__init__.py create mode 100755 mytoninstaller/scripts/add2systemd.sh rename {scripts => mytoninstaller/scripts}/jsonrpcinstaller.sh (62%) mode change 100644 => 100755 rename {scripts => mytoninstaller/scripts}/pytonv3installer.sh (76%) mode change 100644 => 100755 create mode 100755 mytoninstaller/scripts/tonhttpapiinstaller.sh rename mytoninstaller.py => mytoninstaller/settings.py (61%) create mode 100644 mytoninstaller/utils.py create mode 100644 requirements.txt rename scripts/{toninstaller.sh => ton_installer.sh} (63%) mode change 100755 => 100644 delete mode 100644 scripts/upgrade.py create mode 100644 setup.py create mode 100644 tests/__init__.py 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 93% rename from scripts/upgrade.sh rename to mytonctrl/scripts/upgrade.sh index 3f95d73a..35042121 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 63% rename from scripts/toninstaller.sh rename to scripts/ton_installer.sh index 6248acf5..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,43 +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 - -cd $BIN_DIR -rm -rf openssl_3 -git clone https://github.com/openssl/openssl openssl_3 -cd openssl_3 -opensslPath=`pwd` -git checkout openssl-3.1.4 -./config -make build_libs -j12 # Подготавливаем папки для компиляции echo -e "${COLOR}[3/6]${ENDC} Preparing for compilation" @@ -167,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 -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a + cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton fi # Компилируем из исходников @@ -189,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") From b68444fd5989a7b62939b93cc06fc5b3ab55ce6d Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Mon, 25 Sep 2023 17:22:08 +0300 Subject: [PATCH 036/236] bugfix-1 --- mytoncore/mytoncore.py | 1 + setup.py | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index e912adf3..2105513e 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -31,6 +31,7 @@ get_timestamp, timestamp2datetime, dec2hex, + Dict ) diff --git a/setup.py b/setup.py index b0b42415..9bd63b66 100644 --- a/setup.py +++ b/setup.py @@ -5,12 +5,12 @@ long_description = f.read() -version = 'dev' +version = 'v0.0.0' setup( - author='igroman', - author_email='igroman', - name='myton', + author='igroman787', + author_email='igroman787', + name='mytonctrl', version=version, packages=find_packages('.', exclude=['tests']), install_requires=[ From 94b66ca4f23bd58cb1592e8cf2638469ef15663b Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Mon, 25 Sep 2023 17:30:42 +0300 Subject: [PATCH 037/236] bugfix-2 --- mytoncore/mytoncore.py | 2 +- mytonctrl/mytonctrl.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 2105513e..e3370814 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1313,7 +1313,7 @@ def GetNominationControllerLastSentStakeTime(self, addrB64): #end define def IsNominationControllerReadyToStake(self, addrB64): - now = GetTimestamp() + now = get_timestamp() config15 = self.GetConfig15() lastSentStakeTime = self.GetNominationControllerLastSentStakeTime(addrB64) stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 8fb1542c..37cdae6e 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -637,7 +637,7 @@ def PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkT #end define def GetColorTime(datetime, timestamp): - newTimestamp = GetTimestamp() + newTimestamp = get_timestamp() if timestamp > newTimestamp: result = bcolors.green_text(datetime) else: From b321767ba3a6891ee6d51583e0987a3f30c861cf Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Mon, 25 Sep 2023 17:38:45 +0300 Subject: [PATCH 038/236] bugfix-3 --- mytoncore/functions.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index ac40b572..ad92398b 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -14,6 +14,7 @@ b2mb, get_timestamp, get_internet_interface_name, + get_git_hash, get_service_pid, get_load_avg, thr_sleep, @@ -580,6 +581,6 @@ def mytoncore(): from mypylib.mypylib import MyPyClass local = MyPyClass('mytoncore.py') - print('Local DB path:', local.buffer['localdbFileName']) + print('Local DB path:', local.buffer.localdbFileName) Init(local) General(local) From fc9c0a83fc084a2b7b73b809117cad2b154f7fbc Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Mon, 25 Sep 2023 17:42:41 +0300 Subject: [PATCH 039/236] bugfix-4 --- mytoncore/functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index ad92398b..efa14c4d 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -581,6 +581,6 @@ def mytoncore(): from mypylib.mypylib import MyPyClass local = MyPyClass('mytoncore.py') - print('Local DB path:', local.buffer.localdbFileName) + print('Local DB path:', local.buffer.db_path) Init(local) General(local) From 30d608da9e5919de502f64202310278ad29e977f Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Thu, 28 Sep 2023 12:03:45 +0300 Subject: [PATCH 040/236] Fixed PrintTable method --- mytonctrl/mytonctrl.py | 38 ++++++++++---------------------------- 1 file changed, 10 insertions(+), 28 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 37cdae6e..08d22278 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -11,24 +11,6 @@ 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, @@ -678,7 +660,7 @@ def CreatNewWallet(ton, args): table = list() table += [["Name", "Workchain", "Address"]] table += [[wallet.name, wallet.workchain, wallet.addrB64_init]] - PrintTable(table) + print_table(table) #end define def ActivateWallet(local, ton, args): @@ -709,7 +691,7 @@ def PrintWalletsList(ton, args): if account.status != "active": wallet.addrB64 = wallet.addrB64_init table += [[wallet.name, account.status, account.balance, wallet.version, wallet.workchain, wallet.addrB64]] - PrintTable(table) + print_table(table) #end define def ImportWalletFromFile(local, ton, args): @@ -798,9 +780,9 @@ def ViewAccountStatus(ton, args): statusTable += [["Address", "Status", "Version", "Balance"]] statusTable += [[addrB64, account.status, version, account.balance]] historyTable = GetHistoryTable(ton, addrB64, 10) - PrintTable(statusTable) + print_table(statusTable) print() - PrintTable(historyTable) + print_table(historyTable) #end define def ViewAccountHistory(ton, args): @@ -811,7 +793,7 @@ def ViewAccountHistory(ton, args): color_print("{red}Bad args. Usage:{endc} vah ") return table = GetHistoryTable(ton, addr, limit) - PrintTable(table) + print_table(table) #end define def GetHistoryTable(ton, addr, limit): @@ -902,7 +884,7 @@ def PrintBookmarksList(ton, args): addr = item.get("addr") data = item.get("data") table += [[name, type, addr, data]] - PrintTable(table) + print_table(table) #end define def DeleteBookmark(ton, args): @@ -939,7 +921,7 @@ def DeleteBookmark(ton, args): # table += [["Name", "fix me"]] # for item in data: # table += [[item.get("name"), item.get("fix me")]] -# PrintTable(table) +# print_table(table) # #end define # def DeleteAutoTransferRule(args): @@ -970,7 +952,7 @@ def PrintOffersList(ton, args): if isPassed == False: isPassed = bcolors.red_text("false") table += [[hash, votedValidators, wl, approvedPercent_text, isPassed]] - PrintTable(table) + print_table(table) #end define def VoteOffer(ton, args): @@ -1030,7 +1012,7 @@ def PrintComplaintsList(ton, args): if isPassed == False: isPassed = bcolors.red_text("false") table += [[electionId, adnl, Fine_text, votedValidators, approvedPercent_text, isPassed]] - PrintTable(table) + print_table(table) #end define def VoteComplaint(ton, args): @@ -1074,7 +1056,7 @@ def PrintDomainsList(ton, args): endTime = timestamp2datetime(endTime, "%d.%m.%Y") adnlAddr = item.get("adnlAddr") table += [[domainName, walletName, endTime, adnlAddr]] - PrintTable(table) + print_table(table) #end define def ViewDomainStatus(ton, args): From e001996f5451e0b8e3712b81aca859f87b881663 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Fri, 29 Sep 2023 12:20:19 +0300 Subject: [PATCH 041/236] Migrations WIP --- mytonctrl/mytonctrl.py | 5 +++++ mytonctrl/scripts/migrate.sh | 1 + mytonctrl/scripts/update.sh | 13 +++++-------- scripts/install.sh | 10 +++++----- setup.py | 6 ++++-- 5 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 mytonctrl/scripts/migrate.sh diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 08d22278..ebcb3963 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -167,6 +167,8 @@ def inject_globals(func): def PreUp(local, ton): CheckMytonctrlUpdate(local) check_vport(local, ton) + + check_migrations(local, ton) # CheckTonUpdate() #end define @@ -297,6 +299,9 @@ def Upgrade(ton, args): color_print(text) #end define +def check_migrations(local: MyPyClass, ton: MyTonCore): + pass + def CheckMytonctrlUpdate(local): git_path = local.buffer.my_dir result = check_git_update(git_path) diff --git a/mytonctrl/scripts/migrate.sh b/mytonctrl/scripts/migrate.sh new file mode 100644 index 00000000..cc1f786e --- /dev/null +++ b/mytonctrl/scripts/migrate.sh @@ -0,0 +1 @@ +#!/bin/bash \ No newline at end of file diff --git a/mytonctrl/scripts/update.sh b/mytonctrl/scripts/update.sh index e6b3f680..872add57 100644 --- a/mytonctrl/scripts/update.sh +++ b/mytonctrl/scripts/update.sh @@ -30,21 +30,18 @@ ENDC='\033[0m' # Go to work dir cd ${srcdir} + +# uninstall previous version rm -rf ${srcdir}/${repo} +pip3 uninstall -y # Update code echo "https://github.com/${author}/${repo}.git -> ${branch}" -git clone https://github.com/${author}/${repo}.git +git clone --branch ${branch} --recursive 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 daemon-reload systemctl restart mytoncore # Конец diff --git a/scripts/install.sh b/scripts/install.sh index 5d6fc980..12aba8e1 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -107,18 +107,18 @@ fi echo -e "${COLOR}[3/5]${ENDC} Installing MyTonCtrl" echo "https://github.com/${author}/${repo}.git -> ${branch}" +# remove previous installation cd $SOURCES_DIR rm -rf $SOURCES_DIR/mytonctrl +pip3 uninstall -y 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 clone --branch ${branch} --recursive https://github.com/${author}/${repo}.git ${repo} # TODO: return --recursive back when fix libraries git config --global --add safe.directory $SOURCES_DIR/${repo} +cd $SOURCES_DIR/${repo} pip3 install -U . # TODO: make installation from git directly -echo -e "${COLOR}[3/5]${ENDC} Running myton.installer" +echo -e "${COLOR}[3/5]${ENDC} Running mytoninstaller" # DEBUG parent_name=$(ps -p $PPID -o comm=) diff --git a/setup.py b/setup.py index 9bd63b66..88b8e3d8 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ long_description = f.read() -version = 'v0.0.0' +version = 'v0.1' setup( author='igroman787', @@ -33,10 +33,12 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "License :: Other/Proprietary License", "Topic :: Software Development :: Libraries" ], - # url="https://github.com/toncenter/pytonlib", + url="https://github.com/ton-blockchain/mytonctrl", description="MyTonCtrl", long_description_content_type="text/markdown", long_description=long_description, From e3a0be2df433c1bbba756989dce9a1664363ac0a Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Fri, 29 Sep 2023 14:25:58 +0200 Subject: [PATCH 042/236] Migrations --- mytoncore.py | 16 +++++++++ mytonctrl/migrate.py | 50 +++++++++++++++++++++++++++ mytonctrl/migrations/migration_001.sh | 23 ++++++++++++ mytonctrl/mytonctrl.py | 7 ++-- mytonctrl/scripts/migrate.sh | 1 - setup.py | 6 +++- 6 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 mytoncore.py create mode 100644 mytonctrl/migrate.py create mode 100644 mytonctrl/migrations/migration_001.sh delete mode 100644 mytonctrl/scripts/migrate.sh diff --git a/mytoncore.py b/mytoncore.py new file mode 100644 index 00000000..6c6eb9d5 --- /dev/null +++ b/mytoncore.py @@ -0,0 +1,16 @@ +#!/bin/env python3 + +# +# This is a migration script to update from legacy version of MTC +# +import os +import sys + +sys.path.insert(0, '/usr/bin/mytonctrl') # Add path to mytonctrl module + + +from mytonctrl.mytonctrl import run_migrations + +if __name__ == '__main__': + print('Found new version of mytonctrl! Migrating!') + run_migrations() diff --git a/mytonctrl/migrate.py b/mytonctrl/migrate.py new file mode 100644 index 00000000..119fb2ee --- /dev/null +++ b/mytonctrl/migrate.py @@ -0,0 +1,50 @@ +import os +import pkg_resources + +from mypylib.mypylib import MyPyClass +from mytoncore.mytoncore import MyTonCore + +from mypylib.mypylib import ( + run_as_root +) + +from typing import Optional + + +def migrate_to_version_1(local: MyPyClass, ton: MyTonCore): + # get script path + migrate_script_path = pkg_resources.resource_filename('mytonctrl', 'migrations/migration_001.sh') + args = ["/bin/bash", migrate_script_path] + exit_code = run_as_root(args) + if exit_code != 0: + raise RuntimeError(f'Failed to run migration error. Exit code: {exit_code}') + return + + +def migrate(version: 0, local: MyPyClass, ton: MyTonCore): + if version < 1: + local.add_log(f'Running migration {version} -> 1', 'info') + migrate_to_version_1(local, ton) + + +def run_migrations(local: Optional[MyPyClass]=None, ton: Optional[MyTonCore]=None): + if local is None: + local = MyPyClass('mytonctrl.py') + if ton is None: + ton = MyTonCore(MyPyClass('mytoncore.py')) + + # migrations + local.add_log('Running MyTonCtrl migrations', 'info') + + workdir = local.buffer.my_work_dir + local.add_log(f"Workdir: {workdir}", 'info') + + version = 0 + version_file_path = os.path.join(workdir, 'VERSION') + if os.path.exists(version_file_path): + with open(version_file_path, 'r') as f: + version = int(f.read()) + local.add_log(f'Current version: {version}', 'info') + + migrate(version, local, ton) +#end define \ No newline at end of file diff --git a/mytonctrl/migrations/migration_001.sh b/mytonctrl/migrations/migration_001.sh new file mode 100644 index 00000000..10993ce9 --- /dev/null +++ b/mytonctrl/migrations/migration_001.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# installing pip package +if [ -f "setup.py" ]; then + workdir=$(pwd) +else + workdir=/usr/src/mytonctrl +fi + +cd $workdir +pip3 install -U pip . + +# update /usr/bin/mytonctrl +echo " Updating /usr/bin/mytonctrl" +cat < /usr/bin/mytonctrl +#!/bin/bash +/usr/bin/python3 -m mytonctrl \$@ +EOF +chmod +x /usr/bin/mytonctrl + +# update /etc/systemd/system/mytoncore.service +echo " Updating mytoncore service" +sed -i 's\/usr/src/mytonctrl/mytoncore.py\-m mytoncore\g' /etc/systemd/system/mytoncore.service.test diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index ebcb3963..a41445a0 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -40,6 +40,7 @@ GetSwapInfo, GetBinGitHash, ) +from mytonctrl.migrate import run_migrations import sys, getopt, os @@ -168,7 +169,7 @@ def PreUp(local, ton): CheckMytonctrlUpdate(local) check_vport(local, ton) - check_migrations(local, ton) + run_migrations(local, ton) # CheckTonUpdate() #end define @@ -298,9 +299,7 @@ def Upgrade(ton, args): text = "Upgrade - {red}Error{endc}" color_print(text) #end define - -def check_migrations(local: MyPyClass, ton: MyTonCore): - pass + def CheckMytonctrlUpdate(local): git_path = local.buffer.my_dir diff --git a/mytonctrl/scripts/migrate.sh b/mytonctrl/scripts/migrate.sh deleted file mode 100644 index cc1f786e..00000000 --- a/mytonctrl/scripts/migrate.sh +++ /dev/null @@ -1 +0,0 @@ -#!/bin/bash \ No newline at end of file diff --git a/setup.py b/setup.py index 88b8e3d8..6e4a6cf9 100644 --- a/setup.py +++ b/setup.py @@ -22,7 +22,11 @@ ], package_data={ 'mytoninstaller.scripts': ['*.sh'], - 'mytonctrl': ['resources/*', 'scripts/*.sh'], + 'mytonctrl': [ + 'resources/*', + 'scripts/*.sh', + 'migrations/*.sh' + ], '': ['requirements.txt'], }, zip_safe=True, From 1334abed62accb68c77c492111e1da7cd459595a Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Fri, 29 Sep 2023 14:29:45 +0200 Subject: [PATCH 043/236] Fix typo --- mytonctrl/migrations/migration_001.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/migrations/migration_001.sh b/mytonctrl/migrations/migration_001.sh index 10993ce9..c0c5d685 100644 --- a/mytonctrl/migrations/migration_001.sh +++ b/mytonctrl/migrations/migration_001.sh @@ -20,4 +20,4 @@ chmod +x /usr/bin/mytonctrl # update /etc/systemd/system/mytoncore.service echo " Updating mytoncore service" -sed -i 's\/usr/src/mytonctrl/mytoncore.py\-m mytoncore\g' /etc/systemd/system/mytoncore.service.test +sed -i 's\/usr/src/mytonctrl/mytoncore.py\-m mytoncore\g' /etc/systemd/system/mytoncore.service From c421b2fef0c802c142da2d9131ada0a81fe89787 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Fri, 29 Sep 2023 14:36:50 +0200 Subject: [PATCH 044/236] Fix error in update.sh and added version file creation --- mytonctrl/migrate.py | 43 ++++++++++++++++++++----------------- mytonctrl/scripts/update.sh | 2 +- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/mytonctrl/migrate.py b/mytonctrl/migrate.py index 119fb2ee..63fdd38b 100644 --- a/mytonctrl/migrate.py +++ b/mytonctrl/migrate.py @@ -25,26 +25,29 @@ def migrate(version: 0, local: MyPyClass, ton: MyTonCore): if version < 1: local.add_log(f'Running migration {version} -> 1', 'info') migrate_to_version_1(local, ton) + return 1 def run_migrations(local: Optional[MyPyClass]=None, ton: Optional[MyTonCore]=None): - if local is None: - local = MyPyClass('mytonctrl.py') - if ton is None: - ton = MyTonCore(MyPyClass('mytoncore.py')) - - # migrations - local.add_log('Running MyTonCtrl migrations', 'info') - - workdir = local.buffer.my_work_dir - local.add_log(f"Workdir: {workdir}", 'info') - - version = 0 - version_file_path = os.path.join(workdir, 'VERSION') - if os.path.exists(version_file_path): - with open(version_file_path, 'r') as f: - version = int(f.read()) - local.add_log(f'Current version: {version}', 'info') - - migrate(version, local, ton) -#end define \ No newline at end of file + if local is None: + local = MyPyClass('mytonctrl.py') + if ton is None: + ton = MyTonCore(MyPyClass('mytoncore.py')) + + # migrations + local.add_log('Running MyTonCtrl migrations', 'info') + + workdir = local.buffer.my_work_dir + local.add_log(f"Workdir: {workdir}", 'info') + + version = 0 + version_file_path = os.path.join(workdir, 'VERSION') + if os.path.exists(version_file_path): + with open(version_file_path, 'r') as f: + version = int(f.read()) + local.add_log(f'Current version: {version}', 'info') + + new_version = migrate(version, local, ton) + with open(version_file_path, 'w') as f: + f.write(f'{new_version}') +#end define diff --git a/mytonctrl/scripts/update.sh b/mytonctrl/scripts/update.sh index 872add57..463d422c 100644 --- a/mytonctrl/scripts/update.sh +++ b/mytonctrl/scripts/update.sh @@ -33,7 +33,7 @@ cd ${srcdir} # uninstall previous version rm -rf ${srcdir}/${repo} -pip3 uninstall -y +pip3 uninstall -y mytonctrl # Update code echo "https://github.com/${author}/${repo}.git -> ${branch}" From 328e5de4c3fed24d6c642b7db930563539127b1a Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Fri, 29 Sep 2023 14:45:09 +0200 Subject: [PATCH 045/236] Added restart flag --- mytonctrl/migrate.py | 18 +++++++++--------- mytonctrl/mytonctrl.py | 10 ++++++---- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/mytonctrl/migrate.py b/mytonctrl/migrate.py index 63fdd38b..34746566 100644 --- a/mytonctrl/migrate.py +++ b/mytonctrl/migrate.py @@ -22,10 +22,12 @@ def migrate_to_version_1(local: MyPyClass, ton: MyTonCore): def migrate(version: 0, local: MyPyClass, ton: MyTonCore): + restart = False if version < 1: local.add_log(f'Running migration {version} -> 1', 'info') - migrate_to_version_1(local, ton) - return 1 + restart_required = migrate_to_version_1(local, ton) + restart = restart or restart_required + return 1, restart def run_migrations(local: Optional[MyPyClass]=None, ton: Optional[MyTonCore]=None): @@ -34,20 +36,18 @@ def run_migrations(local: Optional[MyPyClass]=None, ton: Optional[MyTonCore]=Non if ton is None: ton = MyTonCore(MyPyClass('mytoncore.py')) - # migrations - local.add_log('Running MyTonCtrl migrations', 'info') + # migrations + version = 0 workdir = local.buffer.my_work_dir - local.add_log(f"Workdir: {workdir}", 'info') - - version = 0 version_file_path = os.path.join(workdir, 'VERSION') if os.path.exists(version_file_path): with open(version_file_path, 'r') as f: version = int(f.read()) - local.add_log(f'Current version: {version}', 'info') - new_version = migrate(version, local, ton) + new_version, restart = migrate(version, local, ton) + with open(version_file_path, 'w') as f: f.write(f'{new_version}') + return restart #end define diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index a41445a0..addff367 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -168,8 +168,6 @@ def inject_globals(func): def PreUp(local, ton): CheckMytonctrlUpdate(local) check_vport(local, ton) - - run_migrations(local, ton) # CheckTonUpdate() #end define @@ -1420,6 +1418,10 @@ def mytonctrl(): ton = MyTonCore(mytoncore_local) console = MyPyConsole() - Init(local, ton, console, sys.argv[1:]) - console.Run() + # migrations + restart = run_migrations(local, ton) + + if not restart: + Init(local, ton, console, sys.argv[1:]) + console.Run() #end define From bce5a0d7e352d4e5205d638f75a310c25dcd6e69 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Fri, 29 Sep 2023 15:36:21 +0200 Subject: [PATCH 046/236] Fixed missing daemon-reload --- mytonctrl/migrations/migration_001.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/mytonctrl/migrations/migration_001.sh b/mytonctrl/migrations/migration_001.sh index c0c5d685..6d792af9 100644 --- a/mytonctrl/migrations/migration_001.sh +++ b/mytonctrl/migrations/migration_001.sh @@ -21,3 +21,4 @@ chmod +x /usr/bin/mytonctrl # update /etc/systemd/system/mytoncore.service echo " Updating mytoncore service" sed -i 's\/usr/src/mytonctrl/mytoncore.py\-m mytoncore\g' /etc/systemd/system/mytoncore.service +systemctl daemon-reload From 8774847015a617f3895c6d9de5f28aabe51819b7 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 29 Sep 2023 22:27:55 +0300 Subject: [PATCH 047/236] rename temp migration file --- mytoncore.py => mytonctrl.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mytoncore.py => mytonctrl.py (100%) diff --git a/mytoncore.py b/mytonctrl.py similarity index 100% rename from mytoncore.py rename to mytonctrl.py From c1bf1854510bb4da57da883905d6c6265a7c57de Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 30 Sep 2023 10:10:35 +0300 Subject: [PATCH 048/236] set migrate version --- scripts/install.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/install.sh b/scripts/install.sh index 12aba8e1..ae5391ce 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -129,5 +129,8 @@ fi echo "User: $user" python3 -m mytoninstaller -m ${mode} -u ${user} -t ${telemetry} --dump ${dump} +# set migrate version +echo "1" > /home/$user/.local/share/mytonctrl/VERSION + echo -e "${COLOR}[4/4]${ENDC} Mytonctrl installation completed" exit 0 From da68205fd6729e3d904c3c156e46d8e0a49f42e4 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 1 Oct 2023 13:16:39 +0300 Subject: [PATCH 049/236] set migrate version bugfix --- scripts/install.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/install.sh b/scripts/install.sh index ae5391ce..11b2e857 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -130,7 +130,12 @@ echo "User: $user" python3 -m mytoninstaller -m ${mode} -u ${user} -t ${telemetry} --dump ${dump} # set migrate version -echo "1" > /home/$user/.local/share/mytonctrl/VERSION +migrate_version=1 +version_dir="/home/${user}/.local/share/mytonctrl" +version_path="${version_dir}/VERSION" +mkdir -p ${version_dir} +echo ${migrate_version} > ${version_path} +chown ${user}:${user} ${version_dir} ${version_path} echo -e "${COLOR}[4/4]${ENDC} Mytonctrl installation completed" exit 0 From 8e038ac69beef95e315dd370c0c1719078b5f5a2 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 11 Oct 2023 22:02:58 +0300 Subject: [PATCH 050/236] bugfix deposit/withdraw to/from pool --- mytoncore/mytoncore.py | 6 +++--- mytonctrl/mytonctrl.py | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index e3370814..a98c0174 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3336,8 +3336,8 @@ def ActivatePool(self, pool, ex=True): raise Exception("ActivatePool error: time out") #end define - def DepositToPool(self, walletName, poolAddr, amount): - wallet = self.GetLocalWallet(walletName) + def DepositToPool(self, poolAddr, amount): + wallet = self.GetValidatorWallet() 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] @@ -3356,7 +3356,7 @@ def WithdrawFromPool(self, poolAddr, amount): def WithdrawFromPoolProcess(self, poolAddr, amount): self.local.add_log("start WithdrawFromPoolProcess function", "debug") - wallet = self.GetLocalWallet() + wallet = self.GetValidatorWallet() 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] diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index addff367..fabe3d68 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1364,13 +1364,12 @@ def GetPoolData(ton, args): def DepositToPool(ton, args): try: - walletName = args[0] - pollAddr = args[1] - amount = float(args[2]) + pollAddr = args[0] + amount = float(args[1]) except: - color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") + color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") return - ton.DepositToPool(walletName, pollAddr, amount) + ton.DepositToPool(pollAddr, amount) color_print("DepositToPool - {green}OK{endc}") #end define From 1b00998cb583e98195354e65d246aaa11f7b9009 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:54:43 +0300 Subject: [PATCH 051/236] complete library transition complete the transition from crc16 library to fastcrc --- mytoncore/mytoncore.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index a98c0174..2dc7bce4 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -6,10 +6,7 @@ import hashlib import struct import psutil -import crc16 # TODO: check this library! -import fastcrc import subprocess - from fastcrc import crc16 from mytoncore.utils import xhex2hex, ng2g @@ -2963,8 +2960,7 @@ def ParseAddrB64(self, addrB64): crc_bytes = b[34:36] crc_data = bytes(b[:34]) crc = int.from_bytes(crc_bytes, "big") - # check_crc = crc16.crc16xmodem(crc_data) - check_crc = fastcrc.crc16.xmodem(crc_data) # TODO: check this library! + check_crc = crc16.xmodem(crc_data) if crc != check_crc: raise Exception("ParseAddrB64 error: crc do not match") #end if From 6b2ec1241d5fb76c018ddc56a4fa1d2b9390612e Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 5 Nov 2023 13:14:54 +0300 Subject: [PATCH 052/236] clcf bugfix --- mytoncore/mytoncore.py | 10 ---------- mytoninstaller/utils.py | 4 +++- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 2dc7bce4..5275953b 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2698,16 +2698,6 @@ def GetItemFromDict(self, data, search): #end for return None #end define - - def GetDomainFromAuction(self, walletName, addr): - wallet = self.GetLocalWallet(walletName) - bocPath = 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 GetDomainFromAuction(self, walletName, addr): wallet = self.GetLocalWallet(walletName) diff --git a/mytoninstaller/utils.py b/mytoninstaller/utils.py index 9b33b732..c811f158 100644 --- a/mytoninstaller/utils.py +++ b/mytoninstaller/utils.py @@ -5,9 +5,11 @@ def GetInitBlock(): + from mypylib.mypylib import MyPyClass from mytoncore import MyTonCore - ton = MyTonCore(None) + mytoncore_local = MyPyClass('mytoncore.py') + ton = MyTonCore(mytoncore_local) initBlock = ton.GetInitBlock() return initBlock # end define From 4e22ad7ef0b61475f145aabadc1b8782e1d5f9e2 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Tue, 28 Nov 2023 14:39:56 +0000 Subject: [PATCH 053/236] Review comments fixed --- mytoninstaller/mytoninstaller.py | 2 +- mytoninstaller/settings.py | 4 ++-- requirements.txt | 1 + scripts/ton_installer.sh | 6 +++--- scripts/uninstall.sh | 2 +- setup.py | 1 + 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index f284e61e..6efb0e1b 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -62,7 +62,7 @@ def inject_globals(func): 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("enable", inject_globals(Enable), "Enable some function: 'FN' - Full node, 'VC' - Validator console, 'LS' - Liteserver, 'DS' - DHT-Server, 'JR' - jsonrpc, 'PT' - ton-http-api. 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") diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index df75edc3..60e3e211 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -92,7 +92,7 @@ def DownloadDump(local): local.add_log("start DownloadDump fuction", "debug") url = "https://dump.ton.org" - dumpSize = requests.get(url + "/dumps/latest.size.archive.txt").text + dumpSize = requests.get(url + "/dumps/latest.tar.size.archive.txt").text print("dumpSize:", dumpSize) needSpace = int(dumpSize) * 3 diskSpace = psutil.disk_usage("/var") @@ -101,7 +101,7 @@ def DownloadDump(local): #end if # apt install - cmd = "apt install plzip pv -y" + cmd = "apt install plzip pv curl -y" os.system(cmd) # download dump diff --git a/requirements.txt b/requirements.txt index bacf8a0e..22953b42 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ requests psutil cryptography fastcrc +jsonpickle diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 8ebab9ad..9a8efa5d 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -37,7 +37,7 @@ if [ "$OSTYPE" == "linux-gnu" ]; then echo "RHEL-based Linux detected." yum install -y epel-release 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 + yum install -y curl 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." @@ -46,11 +46,11 @@ if [ "$OSTYPE" == "linux-gnu" ]; then elif [ -f /etc/arch-release ]; then echo "Arch Linux detected." pacman -Syuy - pacman -S --noconfirm git make cmake clang gflags zlib openssl readline libmicrohttpd python python-pip + pacman -S --noconfirm curl 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 - apt-get install -y build-essential git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev + apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev # Install ninja apt-get install -y ninja-build diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh index a86575cc..9e1f275c 100644 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -59,7 +59,7 @@ fi rm -rf /usr/bin/mytonctrl # removing pip packages -pip3 uninstall -y myton mypylib mypyconsole +pip3 uninstall -y mytonctrl pip3 uninstall -y ton-http-api # Конец diff --git a/setup.py b/setup.py index 6e4a6cf9..d1633ff7 100644 --- a/setup.py +++ b/setup.py @@ -19,6 +19,7 @@ 'psutil', 'cryptography', 'fastcrc', + 'jsonpickle', ], package_data={ 'mytoninstaller.scripts': ['*.sh'], From 84fdcb514e734a63399b31d6140c38385a12309a Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:41:01 +0300 Subject: [PATCH 054/236] Upgrade TON using openssl-3 --- mytonctrl/scripts/upgrade.sh | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 35042121..e85962a6 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -60,15 +60,6 @@ export CC=/usr/bin/clang export CXX=/usr/bin/clang++ export CCACHE_DISABLE=1 -cd ${bindir} -rm -rf openssl_3 -git clone https://github.com/openssl/openssl openssl_3 -cd openssl_3 -opensslPath=`pwd` -git checkout openssl-3.1.4 -./config -make build_libs -j12 - # Update binary cd ${bindir}/${repo} ls --hide=global.config.json | xargs -d '\n' rm -rf @@ -76,7 +67,16 @@ rm -rf .ninja_* memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') let "cpuNumber = memory / 2100000" || cpuNumber=1 -cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a +git clone https://github.com/openssl/openssl openssl_3 +cd openssl_3 +git checkout openssl-3.1.4 +./config +make build_libs -j12 + +cd .. +rootPath=`pwd` + +cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$rootPath/openssl_3/include -DOPENSSL_CRYPTO_LIBRARY=$rootPath/openssl_3/libcrypto.a ninja -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy systemctl restart validator From b729a576a02ec63bca24afdae12ea72021cb3612 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Tue, 28 Nov 2023 14:58:36 +0000 Subject: [PATCH 055/236] Add openssl 3.0 to main install script --- mytonctrl/scripts/upgrade.sh | 2 +- scripts/ton_installer.sh | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index e85962a6..4604b563 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -71,7 +71,7 @@ git clone https://github.com/openssl/openssl openssl_3 cd openssl_3 git checkout openssl-3.1.4 ./config -make build_libs -j12 +make build_libs -j$(nproc) cd .. rootPath=`pwd` diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 9a8efa5d..26c16957 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -100,6 +100,16 @@ rm -rf $BIN_DIR/ton mkdir $BIN_DIR/ton cd $BIN_DIR/ton +# build openssl 3.0 +cd $BIN_DIR +rm -rf openssl_3 +git clone https://github.com/openssl/openssl openssl_3 +cd openssl_3 +opensslPath=`pwd` +git checkout openssl-3.1.4 +./config +make build_libs -j$(nproc) + # Подготовиться к компиляции if [[ "$OSTYPE" =~ darwin.* ]]; then export CMAKE_C_COMPILER=$(which clang) @@ -120,7 +130,7 @@ if [[ "$OSTYPE" =~ darwin.* ]]; then cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton fi else - cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton + cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a fi # Компилируем из исходников From 4230505d5f5db1e579100b7a3974a93e7d9df411 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Sun, 10 Dec 2023 19:51:00 +0000 Subject: [PATCH 056/236] Fix upgrade and install --- mytonctrl/scripts/upgrade.sh | 22 ++++++++++------------ scripts/ton_installer.sh | 25 ++++++++++++------------- 2 files changed, 22 insertions(+), 25 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 4604b563..1ccd87f7 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -52,10 +52,17 @@ fi cd ${srcdir} rm -rf ${srcdir}/${repo} +# compile openssl_3 +git clone --branch openssl-3.1.4 https://github.com/openssl/openssl ${bindir}/openssl_3 +cd ${bindir}/openssl_3 +./config +make build_libs -j$(nproc) +opensslPath=`pwd` + # 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 --branch ${branch} --recursive https://github.com/${author}/${repo}.git +cd ${repo} export CC=/usr/bin/clang export CXX=/usr/bin/clang++ export CCACHE_DISABLE=1 @@ -67,16 +74,7 @@ rm -rf .ninja_* memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') let "cpuNumber = memory / 2100000" || cpuNumber=1 -git clone https://github.com/openssl/openssl openssl_3 -cd openssl_3 -git checkout openssl-3.1.4 -./config -make build_libs -j$(nproc) - -cd .. -rootPath=`pwd` - -cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$rootPath/openssl_3/include -DOPENSSL_CRYPTO_LIBRARY=$rootPath/openssl_3/libcrypto.a +cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a ninja -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy systemctl restart validator diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 26c16957..c8c7b96a 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -87,29 +87,28 @@ fi # Установка компонентов python3 pip3 install psutil crc16 requests +# build openssl 3.0 +echo -e "${COLOR}[2/6]${ENDC} Building OpenSSL 3.0" +rm -rf $BIN_DIR/openssl_3 +git clone --branch openssl-3.1.4 https://github.com/openssl/openssl $BIN_DIR/openssl_3 +cd $BIN_DIR/openssl_3 +opensslPath=`pwd` +git checkout +./config +make build_libs -j$(nproc) + # Клонирование репозиториев с github.com -echo -e "${COLOR}[2/6]${ENDC} Cloning github repository" +echo -e "${COLOR}[3/6]${ENDC} Preparing for compilation" cd $SOURCES_DIR rm -rf $SOURCES_DIR/ton git clone --recursive https://github.com/ton-blockchain/ton.git git config --global --add safe.directory $SOURCES_DIR/ton # Подготавливаем папки для компиляции -echo -e "${COLOR}[3/6]${ENDC} Preparing for compilation" rm -rf $BIN_DIR/ton mkdir $BIN_DIR/ton cd $BIN_DIR/ton -# build openssl 3.0 -cd $BIN_DIR -rm -rf openssl_3 -git clone https://github.com/openssl/openssl openssl_3 -cd openssl_3 -opensslPath=`pwd` -git checkout openssl-3.1.4 -./config -make build_libs -j$(nproc) - # Подготовиться к компиляции if [[ "$OSTYPE" =~ darwin.* ]]; then export CMAKE_C_COMPILER=$(which clang) @@ -147,7 +146,7 @@ else fi echo "use ${cpuNumber} cpus" -make -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy +ninja -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" From f22bae63f733412d11a73a7296e30f8c9be8d914 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Sun, 10 Dec 2023 20:18:05 +0000 Subject: [PATCH 057/236] Fix 2 --- mytonctrl/scripts/upgrade.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 1ccd87f7..2dae65c1 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -48,17 +48,18 @@ else systemctl daemon-reload fi -# Go to work dir -cd ${srcdir} -rm -rf ${srcdir}/${repo} - # compile openssl_3 +rm -rf ${bindir}/openssl_3 git clone --branch openssl-3.1.4 https://github.com/openssl/openssl ${bindir}/openssl_3 cd ${bindir}/openssl_3 ./config make build_libs -j$(nproc) opensslPath=`pwd` +# Go to work dir +cd ${srcdir} +rm -rf ${srcdir}/${repo} + # Update code echo "https://github.com/${author}/${repo}.git -> ${branch}" git clone --branch ${branch} --recursive https://github.com/${author}/${repo}.git From c214bb54cf9a039f325bdae89f9a29a8ad442b2f Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Sun, 10 Dec 2023 20:25:18 +0000 Subject: [PATCH 058/236] Fixed cpu count --- mytonctrl/scripts/upgrade.sh | 2 +- scripts/ton_installer.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 2dae65c1..aed25870 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -73,7 +73,7 @@ cd ${bindir}/${repo} ls --hide=global.config.json | xargs -d '\n' rm -rf rm -rf .ninja_* memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') -let "cpuNumber = memory / 2100000" || cpuNumber=1 +cpuNumber=$(cat /proc/cpuinfo | grep "processor" | wc -l) cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a ninja -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index c8c7b96a..1f7d62f9 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -138,7 +138,7 @@ if [[ "$OSTYPE" =~ darwin.* ]]; then cpuNumber=$(sysctl -n hw.logicalcpu) else memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') - cpuNumber=$(($memory/2100000)) + cpuNumber=$(cat /proc/cpuinfo | grep "processor" | wc -l) if [ ${cpuNumber} == 0 ]; then echo "Warning! insufficient RAM" cpuNumber=1 From 4d51886106fb7e4fe193decb2185d7fa5224b804 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 11 Dec 2023 17:39:56 +0300 Subject: [PATCH 059/236] AddSaveOffer bugfix --- mytoncore/mytoncore.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 5275953b..44f787c8 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2846,8 +2846,8 @@ def WriteBookmarkData(self, bookmark): def GetSaveOffers(self): bname = "saveOffers" saveOffers = self.local.db.get(bname) - if saveOffers is None: - saveOffers = list() + if type(saveOffers) != dict: + saveOffers = dict() self.local.db[bname] = saveOffers return saveOffers #end define @@ -2857,7 +2857,7 @@ def AddSaveOffer(self, offer): offerPseudohash = offer.get("pseudohash") saveOffers = self.GetSaveOffers() if offerHash not in saveOffers: - saveOffers.append(offerHash) + saveOffers[offerHash] = offerPseudohash self.local.save() #end define From e9267539686239e1f50162804f6154f34cc834b7 Mon Sep 17 00:00:00 2001 From: K-Dimentional Tree Date: Tue, 19 Dec 2023 15:27:38 +0000 Subject: [PATCH 060/236] Fixed temp dir --- mytoncore/mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 44f787c8..c99de556 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -65,7 +65,7 @@ def Refresh(self): 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.tempDir = self.local.buffer.my_temp_dir self.nodeName = self.local.db.get("nodeName") if self.nodeName is None: From 4e42eedb639e0fa756b620ddb211696b8439788f Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 25 Dec 2023 17:13:36 +0300 Subject: [PATCH 061/236] add `debug` mode --- mypyconsole | 2 +- mytonctrl/mytonctrl.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mypyconsole b/mypyconsole index a8e8969a..a8f9f569 160000 --- a/mypyconsole +++ b/mypyconsole @@ -1 +1 @@ -Subproject commit a8e8969a6cac6bf96a34655504278d273adad98a +Subproject commit a8f9f56972192247f37ca8f43a5e723e29994c60 diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index fabe3d68..3cea97b3 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -62,7 +62,8 @@ def inject_globals(func): # Create user console console.name = "MyTonCtrl" - console.startFunction = inject_globals(PreUp) + console.startFunction = inject_globals(PreUp) + console.debug = ton.GetSettings("debug") console.AddItem("update", inject_globals(Update), local.translate("update_cmd")) console.AddItem("upgrade", inject_globals(Upgrade), local.translate("upgrade_cmd")) @@ -160,7 +161,7 @@ def inject_globals(func): ton.walletsDir = wallets #end for - local.db.config.logLevel = "debug" + local.db.config.logLevel = "debug" if console.debug else "info" local.db.config.isLocaldbSaving = False local.run() #end define From 0d64eef9c0fa9a0a74103ab620137c9faf4759f4 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 25 Dec 2023 17:20:03 +0300 Subject: [PATCH 062/236] remove installer `lite` mode --- mytoninstaller/mytoninstaller.py | 24 +++++++----------------- scripts/install.sh | 20 ++++---------------- 2 files changed, 11 insertions(+), 33 deletions(-) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 6efb0e1b..67306b9c 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -194,9 +194,6 @@ def General(local): 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] @@ -207,20 +204,13 @@ def General(local): 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 + FirstMytoncoreSettings(local) + FirstNodeSettings(local) + EnableValidatorConsole(local) + EnableLiteServer(local) + BackupVconfig(local) + BackupMconfig(local) + CreateSymlinks(local) #end define diff --git a/scripts/install.sh b/scripts/install.sh index 11b2e857..79e1f316 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -18,7 +18,6 @@ branch="master" show_help_and_exit() { echo 'Supported argumets:' - echo ' -m [lite|full] Choose installation mode' echo ' -c PATH Provide custom config for toninstaller.sh' echo ' -t Disable telemetry' echo ' -i Ignore minimum reqiurements' @@ -41,10 +40,9 @@ ignore=false dump=false -while getopts m:c:tida:r:b: flag +while getopts c:tida:r:b: flag do case "${flag}" in - m) mode=${OPTARG};; c) config=${OPTARG};; t) telemetry=false;; i) ignore=true;; @@ -59,12 +57,6 @@ do 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" @@ -72,12 +64,8 @@ cpus=$(lscpu | grep "CPU(s)" | head -n 1 | 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 -fi -if [ "${mode}" = "full" ] && [ "$ignore" = false ] && ([ "${cpus}" -lt 8 ] || [ "${memory}" -lt 8000000 ]); then - echo "Insufficient resources. Requires a minimum of 8 processors and 8Gb RAM." +if [ "$ignore" = false ] && ([ "${cpus}" -lt 16 ] || [ "${memory}" -lt 64000000 ]); then + echo "Insufficient resources. Requires a minimum of 16 processors and 64Gb RAM." exit 1 fi @@ -127,7 +115,7 @@ if [ "$parent_name" = "sudo" ] || [ "$parent_name" = "su" ]; then user=$(logname) fi echo "User: $user" -python3 -m mytoninstaller -m ${mode} -u ${user} -t ${telemetry} --dump ${dump} +python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} # set migrate version migrate_version=1 From 869ae0d26e79d9fc243d85ac0eb729a92a893709 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 25 Dec 2023 17:29:45 +0300 Subject: [PATCH 063/236] try `check_vport` --- mytonctrl/mytonctrl.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 3cea97b3..403037ca 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -205,7 +205,11 @@ def GetAuthorRepoBranchFromArgs(args): #end define def check_vport(local, ton): - vconfig = ton.GetValidatorConfig() + try: + vconfig = ton.GetValidatorConfig() + except: + local.add_log("GetValidatorConfig error", "error") + return addr = vconfig.addrs.pop() ip = int2ip(addr.ip) with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as client_socket: From ac72a30987dd9343aa77e796eb59ce3d73ba34a0 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 25 Dec 2023 23:14:11 +0300 Subject: [PATCH 064/236] update `GetNetworkName` function --- mytoncore/mytoncore.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index c99de556..10fa55a9 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3523,17 +3523,15 @@ def GetPoolData(self, addrB64): #end define def GetNetworkName(self): - mainnetValidatorsElectedFor = 65536 - mainnetZerostateRootHash = "x55B13F6D0E1D0C34C9C2160F6F918E92D82BF9DDCF8DE2E4C94A3FDF39D15446" - config12 = self.GetConfig(12) - config15 = self.GetConfig15() - validatorsElectedFor = config15["validatorsElectedFor"] - zerostateRootHash = config12["workchains"]["root"]["node"]["value"]["zerostate_root_hash"] - if (zerostateRootHash == mainnetZerostateRootHash and - validatorsElectedFor == mainnetValidatorsElectedFor): + data = self.local.read_db(self.liteClient.configPath) + mainnet_init_block_root_hash = "YRkrcmZMvLBvjanwKCyL3w4oceGPtFfgx8ym1QKCK/4=" + testnet_init_block_root_hash = "gj+B8wb/AmlPk1z1AhVI484rhrUpgSr2oSFIh56VoSg=" + if data.validator.init_block.root_hash == mainnet_init_block_root_hash: return "mainnet" - else: + elif data.validator.init_block.root_hash == testnet_init_block_root_hash: return "testnet" + else: + return "unknown" #end define def GetFunctionBuffer(self, name, timeout=10): From e309a641223804951c33f4a068e4db8ef67f1ee1 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 6 Jan 2024 01:16:54 +0300 Subject: [PATCH 065/236] add new commands add `cleanup` command add `benchmark` command --- mytonctrl/mytonctrl.py | 43 +++++++++++++++-- mytonctrl/progressbar.py | 85 ++++++++++++++++++++++++++++++++++ mytonctrl/scripts/benchmark.sh | 72 ++++++++++++++++++++++++++++ mytonctrl/scripts/cleanup.sh | 35 ++++++++++++++ mytonctrl/scripts/etabar.py | 22 +++++++++ setup.py | 2 +- 6 files changed, 253 insertions(+), 6 deletions(-) create mode 100644 mytonctrl/progressbar.py create mode 100644 mytonctrl/scripts/benchmark.sh create mode 100644 mytonctrl/scripts/cleanup.sh create mode 100644 mytonctrl/scripts/etabar.py diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 403037ca..5e22297d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -28,6 +28,7 @@ color_print, color_text, bcolors, + Dict, MyPyClass ) @@ -111,8 +112,8 @@ def inject_globals(func): 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("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")) @@ -131,10 +132,12 @@ def inject_globals(func): 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("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") + console.AddItem("cleanup", inject_globals(cleanup_validator_db), local.translate("cleanup_cmd")) + console.AddItem("benchmark", inject_globals(run_benchmark), local.translate("benchmark_cmd")) # Process input parameters opts, args = getopt.getopt(argv,"hc:w:",["config=","wallets="]) @@ -302,7 +305,37 @@ def Upgrade(ton, args): text = "Upgrade - {red}Error{endc}" color_print(text) #end define - + +def cleanup_validator_db(ton, args): + cleanup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/cleanup.sh') + run_args = ["bash", cleanup_script_path] + exit_code = run_as_root(run_args) +#end define + +def run_benchmark(ton, args): + timeout = 200 + benchmark_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/benchmark.sh') + etabar_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/etabar.py') + benchmark_result_path = "/tmp/benchmark_result.json" + run_args = ["python3", etabar_script_path, str(timeout), benchmark_script_path, benchmark_result_path] + exit_code = run_as_root(run_args) + if exit_code != 0: + color_print("Benchmark - {red}Error{endc}") + return + #end if + + with open(benchmark_result_path, 'rt') as file: + text = file.read() + data = Dict(json.loads(text)) + #end with + + table = list() + table += [["Test type", "Read speed", "Write speed", "Read iops", "Write iops", "Random ops"]] + table += [["Fio lite", data.lite.read_speed, data.lite.write_speed, data.lite.read_iops, data.lite.write_iops, None]] # RND-4K-QD64 + table += [["Fio hard", data.hard.read_speed, data.hard.write_speed, data.hard.read_iops, data.hard.write_iops, None]] # RND-4K-QD1 + table += [["RocksDB", None, None, None, None, data.full.random_ops]] + print_table(table) +#end define def CheckMytonctrlUpdate(local): git_path = local.buffer.my_dir @@ -1408,7 +1441,7 @@ def UpdateValidatorSet(ton, args): return wallet = ton.GetValidatorWallet() ton.PoolUpdateValidatorSet(poolAddr, wallet) - color_print("DeletePool - {green}OK{endc}") + color_print("UpdateValidatorSet - {green}OK{endc}") #end define diff --git a/mytonctrl/progressbar.py b/mytonctrl/progressbar.py new file mode 100644 index 00000000..a48b3641 --- /dev/null +++ b/mytonctrl/progressbar.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +from os import popen +from time import sleep +from sys import stdout +from threading import Thread + +class EtaBar: + def __init__(self, **kwargs): + self.toolbar_width = kwargs.get("toolbar_width", 10) + self.snake_width = kwargs.get("snake_width", 4) + self.timeout = kwargs.get("timeout", 60) + self.sleep_time = 0.1 + + self.square_symbol = '\u25A0' + self.new_line_symbol = '\r' + self.indent_symbol = ' ' + + self.tty_height, self.tty_width = self.get_tty_size() + #end define + + def run(self, func=None, *args, **kwargs): + if func is None: + func = self.stub + self.start_thread(func, args=args, kwargs=kwargs) + self.snake_process() + return self.thread_result + #end define + + def stub(self): + sleep(self.timeout) + #end define + + def get_tty_size(self): + with popen("stty size", 'r') as file: + tty_height, tty_width = file.read().split() + tty_height = int(tty_height) + tty_width = int(tty_width) + return tty_height, tty_width + #end define + + def start_thread(self, func, **kwargs): + self.thread_result = None + self.thread = Thread(target=self.thread_process, name=func.__name__, args=(func,), kwargs=kwargs, daemon=True) + self.thread.start() + #end define + + def thread_process(self, func, **kwargs): + args = kwargs.get("args") + kwargs = kwargs.get("kwargs") + self.thread_result = func(*args, **kwargs) + #end define + + def snake_process(self): + snake_len = 0 + indent_len = 0 + cycles = int(self.timeout / self.sleep_time) + for cycle in range(cycles): + if self.thread.is_alive() == False: + break + sleep(self.sleep_time) + if indent_len == self.toolbar_width: + indent_len = 0 + elif indent_len == self.toolbar_width - snake_len: + snake_len -= 1 + indent_len += 1 + elif snake_len == self.snake_width: + indent_len += 1 + elif snake_len < self.snake_width: + snake_len += 1 + snake = indent_len * self.indent_symbol + snake_len * self.square_symbol + filling_len = self.toolbar_width - indent_len - snake_len + filling = self.indent_symbol * filling_len + eta = int(self.timeout - cycle * self.sleep_time) + eta_text = f" ETA <= {eta} seconds" + ending_len = self.tty_width - self.toolbar_width - 2 - len(eta_text) + ending = ending_len * self.indent_symbol + text = self.new_line_symbol + '[' + snake + filling + ']' + eta_text + ending + stdout.write(text) + #end for + + stdout.write(self.new_line_symbol + self.indent_symbol * self.tty_width) + stdout.write(self.new_line_symbol) + #end define +#end class diff --git a/mytonctrl/scripts/benchmark.sh b/mytonctrl/scripts/benchmark.sh new file mode 100644 index 00000000..f7f6c323 --- /dev/null +++ b/mytonctrl/scripts/benchmark.sh @@ -0,0 +1,72 @@ +#!/bin/bash +set -e + +# Проверить sudo +if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 +fi + +file_path=/var/ton-work/db/test.img +db_path=/var/ton-work/db/bench + +function get_fio_json { + read_iops=$(echo "$1" | grep "read:" | awk '{print $2}' | awk -F '=' '{print $2}') + write_iops=$(echo "$1" | grep "write:" | awk '{print $2}' | awk -F '=' '{print $2}') + read_iops=$(echo "${read_iops//,/}") + write_iops=$(echo "${write_iops//,/}") + read_speed=$(echo "$1" | grep "read:" | awk '{print $3}' | awk -F '=' '{print $2}') + write_speed=$(echo "$1" | grep "write:" | awk '{print $3}' | awk -F '=' '{print $2}') + json=$(cat <<-END + { + "read_iops": "${read_iops}", + "write_iops": "${write_iops}", + "read_speed": "${read_speed}", + "write_speed": "${write_speed}" + } + END + ) + echo $json +} + +function get_rocksd_bench_json { + random_ops=$(echo "$1" | grep "randomtransaction" | awk '{print $5}') + json=$(cat <<-END + { + "random_ops": "${random_ops}" + } + END + ) + echo $json +} + +function print_json_result { + json=$(cat <<-END + { + "lite": ${lite_json_result}, + "hard": ${hard_json_result}, + "full": ${full_json_result} + } + END + ) + echo $json +} + +# https://superuser.com/questions/1049382/ssd-4k-random-read-write-qd1-32-and-iops-values +# lite +lite_result=$(fio --name=test --runtime=60 --readwrite=randrw --blocksize=4k --ioengine=libaio --direct=1 --size=4G --filename=${file_path} --rwmixread=75 --randrepeat=1 --gtod_reduce=1 --iodepth=64) +lite_json_result=$(get_fio_json "$lite_result") + +# hard +hard_result=$(fio --name=test --runtime=60 --readwrite=randrw --blocksize=4k --ioengine=libaio --direct=1 --size=4G --filename=${file_path} --rwmixread=75 --io_size=10g --fsync=1 --iodepth=1 --numjobs=1) +hard_json_result=$(get_fio_json "$hard_result") + +# full +full_result=$(/usr/bin/db_bench --benchmarks="randomtransaction" -max_background_flushes 2 max_background_compactions 4 -bytes_per_sync 1048576 -writable_file_max_buffer_size 32768 -duration 60 -threads 8 -db=${db_path} 2>/dev/null) +full_json_result=$(get_rocksd_bench_json "$full_result") + +# clear temp files +rm ${file_path} +rm -rf ${db_path} + +print_json_result diff --git a/mytonctrl/scripts/cleanup.sh b/mytonctrl/scripts/cleanup.sh new file mode 100644 index 00000000..d3d10a2e --- /dev/null +++ b/mytonctrl/scripts/cleanup.sh @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +# Проверить sudo +if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 +fi + +# Цвета +COLOR='\033[92m' +ENDC='\033[0m' + +db_path=/var/ton-work/db + +function get_directory_size { + buff=$(du -sh ${db_path} | awk '{print $1}') + echo ${buff} +} + +echo -e "${COLOR}[1/7]${ENDC} Start node/validator DB cleanup process" +echo -e "${COLOR}[2/7]${ENDC} Stop node/validator" +systemctl stop validator + +echo -e "${COLOR}[3/7]${ENDC} Node/validator DB size before cleanup = $(get_directory_size)" +find /var/ton-work/db -name 'LOG.old*' -exec rm {} + + +echo -e "${COLOR}[4/7]${ENDC} Node/validator DB size after deleting old files = $(get_directory_size)" +rm -r /var/ton-work/db/files/packages/temp.archive.* + +echo -e "${COLOR}[5/7]${ENDC} Node/validator DB size after deleting temporary files = $(get_directory_size)" +echo -e "${COLOR}[6/7]${ENDC} Start node/validator" +systemctl start validator + +echo -e "${COLOR}[7/7]${ENDC} Node/validator DB cleanup process completed" diff --git a/mytonctrl/scripts/etabar.py b/mytonctrl/scripts/etabar.py new file mode 100644 index 00000000..b0508e46 --- /dev/null +++ b/mytonctrl/scripts/etabar.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +from sys import exit, argv +from subprocess import run, PIPE +from mytonctrl.progressbar import EtaBar + + +timeout = int(argv[1]) +script = argv[2] +result = argv[3] + +bar = EtaBar(timeout=timeout) +args = ["bash", script] +process = bar.run(run, args, stdin=PIPE, stdout=PIPE, stderr=PIPE, timeout=timeout) +exit_code = -1 +if process != None: + exit_code = process.returncode + stdout = process.stdout.decode("utf-8") + stderr = process.stderr.decode("utf-8") + with open(result, 'wt') as file: + file.write(stdout) +exit(exit_code) diff --git a/setup.py b/setup.py index d1633ff7..b1d3088f 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ 'mytoninstaller.scripts': ['*.sh'], 'mytonctrl': [ 'resources/*', - 'scripts/*.sh', + 'scripts/*', 'migrations/*.sh' ], '': ['requirements.txt'], From 0ff31bf0f96aef36b28ea155eca5ee6dd86caa24 Mon Sep 17 00:00:00 2001 From: Victor Tec Date: Thu, 11 Jan 2024 16:22:07 +0300 Subject: [PATCH 066/236] single nominator fift scripts upload --- .../single-nominator-pool/HOWTO-deploy.md | 25 ++++++ .../contracts/single-nominator-pool/README.md | 53 ++++++++++++ .../change-validator.fif | 22 +++++ .../contracts/single-nominator-pool/init.fif | 39 +++++++++ .../single-nominator-pool/send-raw-msg.fif | 18 ++++ .../single-nominator-pool/snominator-code.hex | 1 + .../single-nominator-pool/upgrade.fif | 16 ++++ .../single-nominator-pool/wallet-v3.fif | 85 +++++++++++++++++++ .../single-nominator-pool/withdraw.fif | 16 ++++ 9 files changed, 275 insertions(+) create mode 100644 mytoncore/contracts/single-nominator-pool/HOWTO-deploy.md create mode 100644 mytoncore/contracts/single-nominator-pool/README.md create mode 100755 mytoncore/contracts/single-nominator-pool/change-validator.fif create mode 100755 mytoncore/contracts/single-nominator-pool/init.fif create mode 100755 mytoncore/contracts/single-nominator-pool/send-raw-msg.fif create mode 100644 mytoncore/contracts/single-nominator-pool/snominator-code.hex create mode 100755 mytoncore/contracts/single-nominator-pool/upgrade.fif create mode 100755 mytoncore/contracts/single-nominator-pool/wallet-v3.fif create mode 100755 mytoncore/contracts/single-nominator-pool/withdraw.fif diff --git a/mytoncore/contracts/single-nominator-pool/HOWTO-deploy.md b/mytoncore/contracts/single-nominator-pool/HOWTO-deploy.md new file mode 100644 index 00000000..104b8897 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/HOWTO-deploy.md @@ -0,0 +1,25 @@ +# Deploy single-nominator-pool + +### 1. Generate state-init +Command: +``` +./init.fif +``` + +Example: +``` +./init.fif snominator-code.hex EQDYDK1NivLsfSVxYE1aUt5xU-behhWSin29vgE7M6wzLMjN Ef8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAU +``` + +### 2. Sign and send a message + +Command: +``` +./wallet-v3.fif 2 -n -I snominator-init.boc +``` + +Example: +``` +./wallet-v3.fif mywallet Ef9rfl-0S4wuAs6-rwl6RgjXznkhQaZNvlq9jMDHBlDpMe8h 698983191 7 1 -n -I snominator-init.boc +``` +Expects to have `mywallet.addr` `mywallet.pk` files. diff --git a/mytoncore/contracts/single-nominator-pool/README.md b/mytoncore/contracts/single-nominator-pool/README.md new file mode 100644 index 00000000..8fd492d6 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/README.md @@ -0,0 +1,53 @@ +# Fift scripts for single-validator contract + +### Init + +usage: `./init.fif ` \ +Creates a state-init to deploy a single-nominator-pool contract. + +`` is a filename of the compiled contract code BoC bytes or HEX. \ +Saves the contract address in `snominator.addr`. \ +Saves the init boc into `snominator-state-init.boc`. + +### Wallet V3 (Modded) + +> A basic [wallet-v3.fif](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/wallet-v3.fif) but with an init-state option for deploy. + +usage: +``` +./wallet-v3.fif + + [-x *] + [-n|-b] [-t] [-B ] + [-C ] [-I ] [] +``` + +Creates a request to advanced wallet created by `new-wallet-v3.fif`, \ +with private key loaded from file `.pk` \ +and address from `.addr`, and saves it \ +into `.boc` (`wallet-query.boc` by default). + +### Withdraw + +usage: `./withdraw.fif ` \ +Creates a message body to withdraw from a single-nominator pool. + +### Upgrade + +usage: `./upgrade.fif ` \ +Creates a message body to update the nominator's code. \ +Takes `` - BoC file path as argument. \ +Saves the result into `upgrade.boc`. + +### Change Validator Address + +usage: `./change-validator.fif ` \ +Creates change validator action msg body BoC. \ +Saves it into `change-validator.boc`. + +### Send Raw Message + +usage: `./send-raw-msg.fif ` \ +Creates a request to send a message through single-nominator-poll. \ +`` - BoC full msg file path. \ +Saves the result msg body into `send-raw-msg.boc`. diff --git a/mytoncore/contracts/single-nominator-pool/change-validator.fif b/mytoncore/contracts/single-nominator-pool/change-validator.fif new file mode 100755 index 00000000..89de84a9 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/change-validator.fif @@ -0,0 +1,22 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include +"GetOpt.fif" include + +{ ."usage: " @' $0 type ." " cr + ."Creates change validator action msg body BoC." cr + ."Saves it into `change-validator.boc`." cr 1 halt +} : usage +$# 1 = { } { usage } cond + +true constant bounce +true =: allow-bounce +false =: force-bounce + +$1 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: to_addr + + =: body_boc +body_boc B +"change-validator.boc" tuck B>file +."(Saved query to file " type .")" cr diff --git a/mytoncore/contracts/single-nominator-pool/init.fif b/mytoncore/contracts/single-nominator-pool/init.fif new file mode 100755 index 00000000..421b8d8f --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/init.fif @@ -0,0 +1,39 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." " cr + ."Creates a state-init to deploy a single-nominator-pool contract." cr cr + + ." is a filename of the compiled contract code BoC bytes or HEX." cr + ."Saves the contract address in `snominator.addr`." cr + ."Saves the init boc into `snominator-state-init.boc`." cr 1 halt +} : usage +$# 3 = { cr } { usage } cond + +$1 =: filename +$2 parse-smc-addr drop 2=: owner-addr +$3 parse-smc-addr drop 2=: validator-addr + +filename file>B dup +8 B| drop B>$ "b5ee9c72" $= { B>$ x>B? drop } if +B>boc =: new-code-boc + +-1 =: wc // masterchain +1 Gram* =: ton-amount + + // data + dup =: init-boc +2 boc+>B +dup ."StateInit: " B>base64 type cr cr +dup ."HEX: " Bx. cr +"snominator-init.boc" tuck B>file +."(Saving nominator init into " type .")" cr cr + +init-boc hashu wc swap 2dup 2=: dest-addr +."New nominator address = " 2dup .addr cr + +2dup "snominator.addr" save-address-verbose cr + +."Non-bounceable address (for init): " 2dup 7 .Addr cr +."Bounceable address (for later access): " 6 .Addr cr cr diff --git a/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif b/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif new file mode 100755 index 00000000..f264fe32 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif @@ -0,0 +1,18 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." " cr cr + ."Creates a request to send a message through single-nominator-poll." cr + ." - BoC full msg file path." cr cr + ."Saves the result msg body into `send-raw-msg.boc`." cr 1 halt +} : usage +$# 2 = { } { usage } cond + +$1 file>B B>boc =: msg +$2 (number) =: mode + + 2 boc+>B +."Message body is " dup B>base64 type cr cr +."HEX: " dup Bx. cr cr + +"send-raw-msg.boc" tuck B>file ."Saved to " type cr diff --git a/mytoncore/contracts/single-nominator-pool/snominator-code.hex b/mytoncore/contracts/single-nominator-pool/snominator-code.hex new file mode 100644 index 00000000..9158fe09 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/snominator-code.hex @@ -0,0 +1 @@ +b5ee9c7241020d010001c5000114ff00f4a413f4bcf2c80b01020162050202012004030015bfe5076a2687d207d2068c0027bdf8cb938b82a38002a380036b6aa39152988b6c0268d0ed44d0fa40fa40d122c700925f06e003d0d3030171b0925f06e0fa403002d31fd33f5343c7059133e30d5235c705925f06e30d0b0604f02082104e73744bba8fe102fa4430f828fa443081200302c0ff12f2f4830c01c0fff2f481200123f2f481200524821047868c00bef2f4fa0020db3c300581200405a182103b9aca00a15210bb14f2f4db3c82104e73744bc8cb1f5230cb3f5005cf16c9443080188040db3c9410356c41e2821047657424ba0a080c0702368f16821047657424c8cb1fcb3fc9db3c705880188040db3c9130e2080c011671f833d0d70bff7f01db3c09001674c8cb0212ca07cbffc9d0001cd3ff31d31fd31f31d3ff31d431d101c422830bba8ea0fa005387a182103b9aca00a112b60881200421c200f2f452406d80188040db3cde22811001ba9efa405044c858cf1601cf16c9ed549133e221817702ba9802d307d402fb0002de2182009903ba9d02d4812002226ef2f201fb0402de0c0048226eb32091719170e203c8cb055006cf165004fa02cb6a039358cc019130e201c901fb007da7d834 diff --git a/mytoncore/contracts/single-nominator-pool/upgrade.fif b/mytoncore/contracts/single-nominator-pool/upgrade.fif new file mode 100755 index 00000000..4ee097b5 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/upgrade.fif @@ -0,0 +1,16 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." " cr cr + ."Creates a message body to update the nominator's code." cr + ."Takes - BoC file path as argument." cr cr + ."Saves the result into `upgrade.boc`." cr 1 halt +} : usage +$# 1 = { } { usage } cond + +$1 file>B B>boc =: new-code-boc + + 2 boc+>B +."Message body is " dup B>base64 type cr + +"upgrade.boc" tuck B>file ."Saved to " type cr diff --git a/mytoncore/contracts/single-nominator-pool/wallet-v3.fif b/mytoncore/contracts/single-nominator-pool/wallet-v3.fif new file mode 100755 index 00000000..f44e0c92 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/wallet-v3.fif @@ -0,0 +1,85 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include +"GetOpt.fif" include + +{ show-options-help 1 halt } : usage + +"" =: comment // comment for simple transfers +true =: allow-bounce +false =: force-bounce +3 =: send-mode // mode for SENDRAWMSG: +1 - sender pays fees, +2 - ignore errors +60 =: timeout // external message expires in 60 seconds +variable extra-currencies +{ extra-currencies @ cc+ extra-currencies ! } : extra-cc+! + +begin-options + " [-x *] [-n|-b] [-t] [-B ] [-C ] [-I ] []" +cr +tab + +"Creates a request to advanced wallet created by new-wallet-v3.fif, with private key loaded from file .pk " + +"and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" + disable-digit-options generic-help-setopt + "n" "--no-bounce" { false =: allow-bounce } short-long-option + "Clears bounce flag" option-help + "b" "--force-bounce" { true =: force-bounce } short-long-option + "Forces bounce flag" option-help + "x" "--extra" { $>xcc extra-cc+! } short-long-option-arg + "Indicates the amount of extra currencies to be transfered" option-help + "t" "--timeout" { parse-int =: timeout } short-long-option-arg + "Sets expiration timeout in seconds (" timeout (.) $+ +" by default)" option-help + "B" "--body" { =: body-boc-file } short-long-option-arg + "Sets the payload of the transfer message" option-help + "C" "--comment" { =: comment } short-long-option-arg + "Sets the comment to be sent in the transfer message" option-help + "I" "--with-init" { =: init-file } short-long-option-arg + "Indicates filename with BoC containing StateInit for internal message" option-help + "m" "--mode" { parse-int =: send-mode } short-long-option-arg + "Sets transfer mode (0..255) for SENDRAWMSG (" send-mode (.) $+ +" by default)" + option-help + "h" "--help" { usage } short-long-option + "Shows a help message" option-help +parse-options + +$# dup 5 < swap 6 > or ' usage if +6 :$1..n + +true constant bounce +$1 =: file-base +$2 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: dest_addr +$3 parse-int =: subwallet_id +$4 parse-int =: seqno +$5 $>cc extra-cc+! extra-currencies @ 2=: amount +$6 "wallet-query" replace-if-null =: savefile +subwallet_id (.) 1 ' $+ does : +subwallet + +file-base +subwallet +".addr" dup file-exists? { drop file-base +".addr" } ifnot +load-address +2dup 2constant wallet_addr +."Source wallet address = " 2dup .addr cr 6 .Addr cr +file-base +".pk" load-keypair nip constant wallet_pk + +def? body-boc-file { @' body-boc-file file>B B>boc } { comment simple-transfer-body } cond +constant body-cell + +def? init-file { @' init-file file>B B>boc + +dup ."signing message: " +dup ."resulting external message: " B dup Bx. cr +savefile +".boc" tuck B>file +."Query expires in " timeout . ."seconds" cr +."(Saved to file " type .")" cr diff --git a/mytoncore/contracts/single-nominator-pool/withdraw.fif b/mytoncore/contracts/single-nominator-pool/withdraw.fif new file mode 100755 index 00000000..96ccfe8e --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/withdraw.fif @@ -0,0 +1,16 @@ +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include + +{ ."usage: " @' $0 type ." " cr + ."Creates a message body to withdraw from a single-nominator pool." cr 1 halt +} : usage +$# 1 = { } { usage } cond + +$1 $>GR =: amount + + =: body_boc +body_boc B +"withdraw.boc" tuck B>file +."(Saved witdhraw query to file to file " type .")" cr From 44d2ffe5d471c5060207dec0c06cf6229ccb7fda Mon Sep 17 00:00:00 2001 From: Victor Tec Date: Fri, 19 Jan 2024 18:54:18 +0300 Subject: [PATCH 067/236] single nominator: enhancements for fift scrips, new code --- mytoncore/contracts/single-nominator-pool/README.md | 3 ++- .../contracts/single-nominator-pool/change-validator.fif | 5 +++-- mytoncore/contracts/single-nominator-pool/init.fif | 2 +- mytoncore/contracts/single-nominator-pool/send-raw-msg.fif | 4 ++-- .../contracts/single-nominator-pool/snominator-code.hex | 2 +- mytoncore/contracts/single-nominator-pool/upgrade.fif | 6 ++++-- mytoncore/contracts/single-nominator-pool/withdraw.fif | 2 +- 7 files changed, 14 insertions(+), 10 deletions(-) diff --git a/mytoncore/contracts/single-nominator-pool/README.md b/mytoncore/contracts/single-nominator-pool/README.md index 8fd492d6..67c03df8 100644 --- a/mytoncore/contracts/single-nominator-pool/README.md +++ b/mytoncore/contracts/single-nominator-pool/README.md @@ -41,7 +41,8 @@ Saves the result into `upgrade.boc`. ### Change Validator Address -usage: `./change-validator.fif ` \ +usage: `./change-validator.fif ` \ +Takes user friendly address as parameter - not file. \ Creates change validator action msg body BoC. \ Saves it into `change-validator.boc`. diff --git a/mytoncore/contracts/single-nominator-pool/change-validator.fif b/mytoncore/contracts/single-nominator-pool/change-validator.fif index 89de84a9..478e08f5 100755 --- a/mytoncore/contracts/single-nominator-pool/change-validator.fif +++ b/mytoncore/contracts/single-nominator-pool/change-validator.fif @@ -3,7 +3,8 @@ "Asm.fif" include "GetOpt.fif" include -{ ."usage: " @' $0 type ." " cr +{ ."usage: " @' $0 type ." " cr + ."Takes user friendly address as parameter - not file." cr ."Creates change validator action msg body BoC." cr ."Saves it into `change-validator.boc`." cr 1 halt } : usage @@ -15,7 +16,7 @@ false =: force-bounce $1 bounce parse-load-address force-bounce or allow-bounce and =: bounce 2=: to_addr - =: body_boc + =: body_boc body_boc B "change-validator.boc" tuck B>file diff --git a/mytoncore/contracts/single-nominator-pool/init.fif b/mytoncore/contracts/single-nominator-pool/init.fif index 421b8d8f..4cb13918 100755 --- a/mytoncore/contracts/single-nominator-pool/init.fif +++ b/mytoncore/contracts/single-nominator-pool/init.fif @@ -6,7 +6,7 @@ ." is a filename of the compiled contract code BoC bytes or HEX." cr ."Saves the contract address in `snominator.addr`." cr - ."Saves the init boc into `snominator-state-init.boc`." cr 1 halt + ."Saves the init boc into `snominator-init.boc`." cr 1 halt } : usage $# 3 = { cr } { usage } cond diff --git a/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif b/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif index f264fe32..f6becdbc 100755 --- a/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif +++ b/mytoncore/contracts/single-nominator-pool/send-raw-msg.fif @@ -9,9 +9,9 @@ $# 2 = { } { usage } cond $1 file>B B>boc =: msg -$2 (number) =: mode +$2 (number) 1 <> abort"not an integer: check your send-mode" =: mode - 2 boc+>B + 2 boc+>B ."Message body is " dup B>base64 type cr cr ."HEX: " dup Bx. cr cr diff --git a/mytoncore/contracts/single-nominator-pool/snominator-code.hex b/mytoncore/contracts/single-nominator-pool/snominator-code.hex index 9158fe09..ee02a24e 100644 --- a/mytoncore/contracts/single-nominator-pool/snominator-code.hex +++ b/mytoncore/contracts/single-nominator-pool/snominator-code.hex @@ -1 +1 @@ -b5ee9c7241020d010001c5000114ff00f4a413f4bcf2c80b01020162050202012004030015bfe5076a2687d207d2068c0027bdf8cb938b82a38002a380036b6aa39152988b6c0268d0ed44d0fa40fa40d122c700925f06e003d0d3030171b0925f06e0fa403002d31fd33f5343c7059133e30d5235c705925f06e30d0b0604f02082104e73744bba8fe102fa4430f828fa443081200302c0ff12f2f4830c01c0fff2f481200123f2f481200524821047868c00bef2f4fa0020db3c300581200405a182103b9aca00a15210bb14f2f4db3c82104e73744bc8cb1f5230cb3f5005cf16c9443080188040db3c9410356c41e2821047657424ba0a080c0702368f16821047657424c8cb1fcb3fc9db3c705880188040db3c9130e2080c011671f833d0d70bff7f01db3c09001674c8cb0212ca07cbffc9d0001cd3ff31d31fd31f31d3ff31d431d101c422830bba8ea0fa005387a182103b9aca00a112b60881200421c200f2f452406d80188040db3cde22811001ba9efa405044c858cf1601cf16c9ed549133e221817702ba9802d307d402fb0002de2182009903ba9d02d4812002226ef2f201fb0402de0c0048226eb32091719170e203c8cb055006cf165004fa02cb6a039358cc019130e201c901fb007da7d834 +b5ee9c7241020d010001f0000114ff00f4a413f4bcf2c80b01020162050202012004030015bfe5076a2687d207d2068c0027bdf8cb938b82a38002a380036b6aa39152988b6c02bcd0ed44d0fa40fa40d122c700925f06e003d0d3030171b0925f06e0fa403002d31f7022c000228b1778c705b022d74ac000b08e136c21830bc85376a182103b9aca00a1fa02c9d09430d33f12e25343c7059133e30d5235c705925f06e30d0b0604f22382104e73744bba8fe102fa4430f828fa443081200302c0ff12f2f4830c01c0fff2f481200122f2f481200524821047868c00bef2f4fa0020db3c300581200405a182103b9aca00a15210bb14f2f4db3c82104e73744bc8cb1f5220cb3f5005cf16c9443080188040db3c9410356c41e201821047657424ba0a080c0702368f16821047657424c8cb1fcb3fc9db3c705880188040db3c9130e2080c011671f833d0d70bff7f01db3c09001674c8cb0212ca07cbffc9d0001cd3ff31d31fd31f31d3ff31d431d101c421830bba8ea0fa005387a182103b9aca00a112b60881200421c200f2f452406d80188040db3cde21811001ba9efa405044c858cf1601cf16c9ed549133e220817702ba9802d307d402fb0002de2082009903ba9d02d4812002226ef2f201fb0402de0c0048226eb32091719170e203c8cb055006cf165004fa02cb6a039358cc019130e201c901fb00fb5470d1 diff --git a/mytoncore/contracts/single-nominator-pool/upgrade.fif b/mytoncore/contracts/single-nominator-pool/upgrade.fif index 4ee097b5..cb426327 100755 --- a/mytoncore/contracts/single-nominator-pool/upgrade.fif +++ b/mytoncore/contracts/single-nominator-pool/upgrade.fif @@ -8,9 +8,11 @@ } : usage $# 1 = { } { usage } cond -$1 file>B B>boc =: new-code-boc +$1 file>B dup +8 B| drop B>$ "b5ee9c72" $= { B>$ x>B? drop } if +B>boc =: new-code-boc - 2 boc+>B + 2 boc+>B ."Message body is " dup B>base64 type cr "upgrade.boc" tuck B>file ."Saved to " type cr diff --git a/mytoncore/contracts/single-nominator-pool/withdraw.fif b/mytoncore/contracts/single-nominator-pool/withdraw.fif index 96ccfe8e..fa8a0976 100755 --- a/mytoncore/contracts/single-nominator-pool/withdraw.fif +++ b/mytoncore/contracts/single-nominator-pool/withdraw.fif @@ -9,7 +9,7 @@ $# 1 = { } { usage } cond $1 $>GR =: amount - =: body_boc + =: body_boc body_boc B "withdraw.boc" tuck B>file From e23ed31de7c5f48a5c5b6228496301a3e9f9e779 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:25:58 +0300 Subject: [PATCH 068/236] add single nominator scripts --- mytoncore/contracts/__init__.py | 0 .../contracts/single-nominator-pool/build.sh | 2 + .../contracts/single-nominator-pool/init.fif | 17 +- .../single-nominator-code.fc | 212 ++++++++++++++++ ...tor-code.hex => single-nominator-code.hex} | 0 mytoncore/modules/single-nominator.py | 239 ++++++++++++++++++ mytonctrl/mytonctrl.py | 28 -- setup.py | 1 + 8 files changed, 463 insertions(+), 36 deletions(-) create mode 100644 mytoncore/contracts/__init__.py create mode 100644 mytoncore/contracts/single-nominator-pool/build.sh create mode 100644 mytoncore/contracts/single-nominator-pool/single-nominator-code.fc rename mytoncore/contracts/single-nominator-pool/{snominator-code.hex => single-nominator-code.hex} (100%) create mode 100644 mytoncore/modules/single-nominator.py diff --git a/mytoncore/contracts/__init__.py b/mytoncore/contracts/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mytoncore/contracts/single-nominator-pool/build.sh b/mytoncore/contracts/single-nominator-pool/build.sh new file mode 100644 index 00000000..b7f3c5df --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/build.sh @@ -0,0 +1,2 @@ +/usr/bin/ton/crypto/func -APS /usr/src/ton/crypto/smartcont/stdlib.fc snominator-code.fc -W snominator-code.boc -o snominator-code.fif +/usr/bin/ton/crypto/fift snominator-code.fif diff --git a/mytoncore/contracts/single-nominator-pool/init.fif b/mytoncore/contracts/single-nominator-pool/init.fif index 421b8d8f..69624e9d 100755 --- a/mytoncore/contracts/single-nominator-pool/init.fif +++ b/mytoncore/contracts/single-nominator-pool/init.fif @@ -1,18 +1,19 @@ #!/usr/bin/fift -s "TonUtil.fif" include -{ ."usage: " @' $0 type ." " cr +{ ."usage: " @' $0 type ." " cr ."Creates a state-init to deploy a single-nominator-pool contract." cr cr ." is a filename of the compiled contract code BoC bytes or HEX." cr - ."Saves the contract address in `snominator.addr`." cr - ."Saves the init boc into `snominator-state-init.boc`." cr 1 halt + ."Saves the contract address in `.addr`." cr + ."Saves the init boc into `-init.boc`." cr 1 halt } : usage -$# 3 = { cr } { usage } cond +$# 4 = { cr } { usage } cond $1 =: filename $2 parse-smc-addr drop 2=: owner-addr $3 parse-smc-addr drop 2=: validator-addr +$4 =: file-base filename file>B dup 8 B| drop B>$ "b5ee9c72" $= { B>$ x>B? drop } if @@ -27,13 +28,13 @@ B>boc =: new-code-boc 2 boc+>B dup ."StateInit: " B>base64 type cr cr dup ."HEX: " Bx. cr -"snominator-init.boc" tuck B>file -."(Saving nominator init into " type .")" cr cr +file-base +"-init.boc" tuck B>file +."(Saved single nominator pool init into " type .")" cr cr init-boc hashu wc swap 2dup 2=: dest-addr -."New nominator address = " 2dup .addr cr +."New pool address = " 2dup .addr cr -2dup "snominator.addr" save-address-verbose cr +2dup file-base +".addr" save-address-verbose cr ."Non-bounceable address (for init): " 2dup 7 .Addr cr ."Bounceable address (for later access): " 6 .Addr cr cr diff --git a/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc b/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc new file mode 100644 index 00000000..48734ca4 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc @@ -0,0 +1,212 @@ +;; https://github.com/orbs-network/single-nominator/blob/main/contracts/single-nominator.fc +;; this contract is very similar to https://github.com/ton-blockchain/nominator-pool but much simpler since it only supports a single nominator +;; frankly speaking, we tried using nominator-pool but it's so complicated that we couldn't be sure there were no bugs hiding around +;; this contract is very simple and easy to review, it is laser focused on protecting your stake and nothing else! + +;; =============== consts ============================= + +const BOUNCEABLE = 0x18; +const ADDRESS_SIZE = 256; +const MIN_TON_FOR_STORAGE = 1000000000; ;; 10% from nominator-pool since we have a single cell +const MIN_TON_FOR_SEND_MSG = 1200000000; + +;; owner ops +const OP::WITHDRAW = 0x1000; +const OP::CHANGE_VALIDATOR_ADDRESS = 0x1001; +const OP::SEND_RAW_MSG = 0x7702; +const OP::UPGRADE = 0x9903; + +;; elector ops +const OP::NEW_STAKE = 0x4e73744b; +const OP::RECOVER_STAKE = 0x47657424; + +;; modes +const MODE::SEND_MODE_REMAINING_AMOUNT = 64; + +;; errors +const ERROR::WRONG_NOMINATOR_WC = 0x2000; +const ERROR::WRONG_QUERY_ID = 0x2001; +const ERROR::WRONG_SET_CODE = 0x2002; +const ERROR::WRONG_VALIDATOR_WC = 0x2003; +const ERROR::INSUFFICIENT_BALANCE = 0x2004; +const ERROR::INSUFFICIENT_ELECTOR_FEE = 0x2005; + +;; =============== storage ============================= + +;; storage#_ owner_address:MsgAddressInt validator_address:MsgAddressInt = Storage + +(slice, slice) load_data() inline { + slice ds = get_data().begin_parse(); + + slice owner_address = ds~load_msg_addr(); + slice validator_address = ds~load_msg_addr(); + + ds.end_parse(); + + return (owner_address, validator_address); +} + +() save_data(slice owner_address, slice validator_address) impure inline { + set_data(begin_cell() + .store_slice(owner_address) + .store_slice(validator_address) + .end_cell()); +} + +;; =============== messages ============================= + +;; defined below +() send_msg(slice to_address, int amount, cell payload, int flags, int send_mode) impure inline_ref; +slice make_address(int wc, int addr) inline_ref; +slice elector_address() inline_ref; +int check_new_stake_msg(slice cs) impure inline_ref; + +;; main entry point for receiving messages +;; my_balance contains balance after adding msg_value +() recv_internal(int my_balance, int msg_value, cell in_msg_full, slice in_msg_body) impure { + var (owner_address, validator_address) = load_data(); + + if (in_msg_body.slice_empty?()) { + return (); + } + + slice cs = in_msg_full.begin_parse(); + int flags = cs~load_uint(4); ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + if (flags & 1) { + ;; ignore all bounced messages + return (); + } + slice sender = cs~load_msg_addr(); + + int op = in_msg_body~load_uint(32); + int query_id = in_msg_body~load_uint(64); + + ;; owner role - cold wallet (private key that is not connected to the internet) that owns the funds used for staking and acts as the single nominator + if (equal_slice_bits(sender, owner_address)) { + + ;; allow owner to withdraw funds - take the money home and stop validating with it + if (op == OP::WITHDRAW) { + int amount = in_msg_body~load_coins(); + amount = min(amount, my_balance - msg_value - MIN_TON_FOR_STORAGE); + throw_unless(ERROR::INSUFFICIENT_BALANCE, amount > 0); + send_msg(owner_address, amount, null(), BOUNCEABLE, MODE::SEND_MODE_REMAINING_AMOUNT); ;; owner pays gas fees + } + + ;; mainly used when the validator was compromised to prevent validator from entering new election cycles + if (op == OP::CHANGE_VALIDATOR_ADDRESS) { + slice new_validator_address = in_msg_body~load_msg_addr(); + save_data(owner_address, new_validator_address); + } + + ;; emergency safeguard to allow owner to send arbitrary messages as the nominator contract + if (op == OP::SEND_RAW_MSG) { + int mode = in_msg_body~load_uint(8); + cell msg = in_msg_body~load_ref(); + send_raw_message(msg, mode); + } + + ;; second emergency safeguard to allow owner to replace nominator logic - you should never need to use this + if (op == OP::UPGRADE) { + cell code = in_msg_body~load_ref(); + throw_if(ERROR::WRONG_SET_CODE, cell_null?(code)); + set_code(code); + } + } + + ;; validator role - the wallet whose private key is on the validator node (can sign blocks but can't steal the funds used for stake) + if (equal_slice_bits(sender, validator_address)) { + + ;; send stake to the elector for the next validation cycle (sent every period ~18 hours) + if (op == OP::NEW_STAKE) { + (int sender_wc, _) = parse_std_addr(sender); + (int my_wc, _) = parse_std_addr(my_address()); + throw_unless(ERROR::WRONG_VALIDATOR_WC, sender_wc == -1); ;; for voting purpose + throw_unless(ERROR::WRONG_NOMINATOR_WC, my_wc == -1); ;; must be deployed on masterchain + throw_unless(ERROR::WRONG_QUERY_ID, query_id); ;; query_id must be greater then 0 to receive confirmation message from elector + throw_unless(ERROR::INSUFFICIENT_ELECTOR_FEE, msg_value >= MIN_TON_FOR_SEND_MSG); ;; must be greater then new_stake sending to elector fee + int stake_amount = in_msg_body~load_coins(); + slice msg = in_msg_body; + check_new_stake_msg(in_msg_body); + throw_unless(ERROR::INSUFFICIENT_BALANCE, stake_amount <= my_balance - msg_value - MIN_TON_FOR_STORAGE); + + send_msg(elector_address(), stake_amount, begin_cell().store_uint(OP::NEW_STAKE, 32).store_uint(query_id, 64).store_slice(msg).end_cell(), BOUNCEABLE, MODE::SEND_MODE_REMAINING_AMOUNT); ;; bounceable, validator pays gas fees + } + + ;; recover stake from elector of previous validation cycle (sent every period ~18 hours) + if (op == OP::RECOVER_STAKE) { + cell payload = begin_cell().store_uint(OP::RECOVER_STAKE, 32).store_uint(query_id, 64).end_cell(); + send_msg(elector_address(), 0, payload, BOUNCEABLE, MODE::SEND_MODE_REMAINING_AMOUNT); ;; bounceable, validator pays gas fees + } + } +} + +;; taken from nominator-pool: https://github.com/ton-blockchain/nominator-pool/blob/2f35c36b5ad662f10fd7b01ef780c3f1949c399d/func/pool.fc#L217 +() send_msg(slice to_address, int amount, cell payload, int flags, int send_mode) impure inline_ref { + int has_payload = ~ cell_null?(payload); + + builder msg = begin_cell() + .store_uint(flags, 6) + .store_slice(to_address) + .store_coins(amount) + .store_uint(has_payload ? 1 : 0, 1 + 4 + 4 + 64 + 32 + 1 + 1); + + if (has_payload) { + msg = msg.store_ref(payload); + } + + send_raw_message(msg.end_cell(), send_mode); +} + +;; taken from nominator-pool: https://github.com/ton-blockchain/nominator-pool/blob/2f35c36b5ad662f10fd7b01ef780c3f1949c399d/func/pool.fc#L68 +slice make_address(int wc, int addr) inline_ref { + return begin_cell() + .store_uint(4, 3).store_int(wc, 8).store_uint(addr, ADDRESS_SIZE).end_cell().begin_parse(); +} + +;; taken from nominator-pool: https://github.com/ton-blockchain/nominator-pool/blob/2f35c36b5ad662f10fd7b01ef780c3f1949c399d/func/pool.fc#L78 +slice elector_address() inline_ref { + int elector = config_param(1).begin_parse().preload_uint(ADDRESS_SIZE); + return make_address(-1, elector); +} + +;; taken from nominator-pool: https://github.com/ton-blockchain/nominator-pool/blob/2f35c36b5ad662f10fd7b01ef780c3f1949c399d/func/pool.fc#L139 +;; check the validity of the new_stake message +;; https://github.com/ton-blockchain/ton/blob/b38d227a469666d83ac535ad2eea80cb49d911b8/crypto/smartcont/elector-code.fc#L208 +int check_new_stake_msg(slice cs) impure inline_ref { + var validator_pubkey = cs~load_uint(256); + var stake_at = cs~load_uint(32); + var max_factor = cs~load_uint(32); + var adnl_addr = cs~load_uint(256); + var signature = cs~load_ref().begin_parse().preload_bits(512); + cs.end_parse(); + return stake_at; ;; supposed start of next validation round (utime_since) +} + +;; =============== getters ============================= + +(slice, slice) get_roles() method_id { + var (owner_address, validator_address) = load_data(); + return (owner_address, validator_address); +} + +;; nominator-pool interface with mytonctrl: https://github.com/ton-blockchain/nominator-pool/blob/2f35c36b5ad662f10fd7b01ef780c3f1949c399d/func/pool.fc#L198 +;; since we are relying on the existing interface between mytonctrl and nominator-pool, we return values that instruct mytonctrl +;; to recover stake on every cycle, although mytonctrl samples every 10 minutes we assume its current behavior that new_stake +;; and recover_stake are only sent once per cycle and don't waste gas +(int, int, int, int, (int, int, int, int, int), cell, cell, int, int, int, int, int, cell) get_pool_data() method_id { + return ( + 2, ;; state - funds staked at elector and should be recovered by mytonctrl + 1, ;; nominators_count - owner is the single nominator + 0, ;; stake_amount_sent - unused, mytonctrl does not rely on this param + 0, ;; validator_amount - unused, since gas is always paid by validator there is no concept of validator_amount + (0, 0, 0, 0, 0), ;; pool config - unused, since not inviting third party nominators + null(), ;; nominators - unused, mytonctrl does not rely on this param + null(), ;; withdraw_requests - unused, not needed since owner controls the validator + 0, ;; stake_at - unused, mytonctrl does not rely on this param + 0, ;; saved_validator_set_hash - unused, required for maintaining validator_amount that we don't need + 2, ;; validator_set_changes_count - funds staked at elector and should be recovered by mytonctrl + 0, ;; validator_set_change_time - back in the past so mytonctrl will always attempt to recover stake + 0, ;; stake_held_for - back in the past so mytonctrl will always attempt to recover stake + null() ;; config_proposal_votings - unused, not needed since owner controls the validator + ); +} diff --git a/mytoncore/contracts/single-nominator-pool/snominator-code.hex b/mytoncore/contracts/single-nominator-pool/single-nominator-code.hex similarity index 100% rename from mytoncore/contracts/single-nominator-pool/snominator-code.hex rename to mytoncore/contracts/single-nominator-pool/single-nominator-code.hex diff --git a/mytoncore/modules/single-nominator.py b/mytoncore/modules/single-nominator.py new file mode 100644 index 00000000..84528c12 --- /dev/null +++ b/mytoncore/modules/single-nominator.py @@ -0,0 +1,239 @@ +import pkg_resources + +def create_single_nominator_pool(self, pool_name, owner_address): + self.local.add_log("start create_single_nominator_pool function", "debug") + + file_path = self.poolsDir + pool_name + if os.path.isfile(file_path + ".addr"): + self.local.add_log("create_single_nominator_pool warning: Pool already exists: " + file_path, "warning") + return + #end if + + fift_script = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/init.fif') + validator_wallet = self.GetValidatorWallet() + args = [fift_script, owner_address, validator_wallet.addrB64, file_path] + result = self.fift.Run(args) + if "Saved single nominator pool" not in result: + raise Exception("create_single_nominator_pool error: " + result) + #end if + + pools = self.get_single_pools() + new_pool = self.get_single_local_pool(pool_name) + for pool in pools: + if pool.name != new_pool.name and pool.addrB64 == new_pool.addrB64: + new_pool.Delete() + raise Exception("create_single_nominator_pool error: Pool with the same parameters already exists.") + #end for +#end define + +def activate_pool(self, pool, ex=True): + self.local.add_log("start activate_pool function", "debug") + for i in range(10): + time.sleep(3) + account = self.GetAccount(pool.addrB64) + if account.balance > 0: + self.SendFile(pool.bocFilePath, pool, timeout=False) + return + if ex: + raise Exception("activate_pool error: time out") +#end define + +def DepositToPool(self, poolAddr, amount): + wallet = self.GetValidatorWallet() + 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) + resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, amount) + self.SendFile(resultFilePath, wallet) +#end define + +def WithdrawFromPool(self, poolAddr, amount): + poolData = self.GetPoolData(poolAddr) + if poolData["state"] == 0: + self.WithdrawFromPoolProcess(poolAddr, amount) + else: + self.PendWithdrawFromPool(poolAddr, amount) +#end define + +def WithdrawFromPoolProcess(self, poolAddr, amount): + self.local.add_log("start WithdrawFromPoolProcess function", "debug") + wallet = self.GetValidatorWallet() + 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) + resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, 1.35) + self.SendFile(resultFilePath, wallet) +#end define + +def PendWithdrawFromPool(self, poolAddr, amount): + self.local.add_log("start PendWithdrawFromPool function", "debug") + pendingWithdraws = self.GetPendingWithdraws() + pendingWithdraws[poolAddr] = amount + self.local.save() +#end define + +def HandlePendingWithdraw(self, pendingWithdraws, poolAddr): + amount = pendingWithdraws.get(poolAddr) + self.WithdrawFromPoolProcess(poolAddr, amount) + pendingWithdraws.pop(poolAddr) +#end define + +def GetPendingWithdraws(self): + bname = "pendingWithdraws" + pendingWithdraws = self.local.db.get(bname) + if pendingWithdraws is None: + pendingWithdraws = dict() + self.local.db[bname] = pendingWithdraws + return pendingWithdraws +#end define + +def SignElectionRequestWithPoolWithValidator(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): + 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] + result = self.fift.Run(args) + pubkey = parse(result, "validator public key ", '\n') + fileName = parse(result, "Saved to file ", '\n') + return pubkey, fileName +#end define + +def PoolProcessRecoverStake(self): + 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] + result = self.fift.Run(args) + resultFilePath = parse(result, "Saved to file ", '\n') + 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 get_single_local_pool(self, pool_name): + self.local.add_log("start get_single_local_pool function", "debug") + if pool_name is None: + return None + filePath = self.poolsDir + pool_name + + # Create pool object + pool = Pool(pool_name, filePath) + if os.path.isfile(pool.addrFilePath) == False: + raise Exception(f"get_single_local_pool error: Address file not found: {pool.addrFilePath}") + #end if + + self.AddrFile2Object(pool) + return pool +#end define + +def GetPoolsNameList(self): + self.local.add_log("start GetPoolsNameList function", "debug") + poolsNameList = list() + for fileName in os.listdir(self.poolsDir): + if fileName.endswith(".addr"): + fileName = fileName[:fileName.rfind('.')] + poolsNameList.append(fileName) + poolsNameList.sort() + return poolsNameList +#end define + +def get_single_pools(self): + self.local.add_log("start get_single_pools function", "debug") + pools = list() + poolsNameList = self.GetPoolsNameList() + for pool_name in poolsNameList: + pool = self.get_single_local_pool(pool_name) + pools.append(pool) + return pools +#end define + +def GetPool(self, mode): + pools = self.get_single_pools() + for pool in pools: + if mode == "stake" and self.IsPoolReadyToStake(pool.addrB64): + return pool + if mode == "vote" and self.IsPoolReadyToVote(pool.addrB64): + return pool + raise Exception("Validator pool not found or not ready") +#end define + +def GetPoolLastSentStakeTime(self, addrB64): + poolData = self.GetPoolData(addrB64) + return poolData["stakeAt"] +#end define + +def IsPoolReadyToStake(self, addrB64): + now = get_timestamp() + config15 = self.GetConfig15() + lastSentStakeTime = self.GetPoolLastSentStakeTime(addrB64) + stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] + result = lastSentStakeTime + stakeFreezeDelay < now + print(f"{addrB64}: {result}. {lastSentStakeTime}, {stakeFreezeDelay}, {now}") + return result +#end define + +def IsPoolReadyToVote(self, addrB64): + vwl = self.GetValidatorsWalletsList() + result = addrB64 in vwl + return result +#end define + +def GetPoolData(self, addrB64): + self.local.add_log("start GetPoolData function", "debug") + cmd = f"runmethodfull {addrB64} get_pool_data" + result = self.liteClient.Run(cmd) + data = self.Result2List(result) + if data is None: + return + poolConfig = dict() + poolConfig["validatorAddress"] = data[4] + poolConfig["validatorRewardShare"] = data[5] + poolConfig["validatorRewardSharePercent"] = data[5] / 100 + poolConfig["maxNominatorsCount"] = data[6] + poolConfig["minValidatorStake"] = ng2g(data[7]) + poolConfig["minNominatorStake"] = ng2g(data[8]) + poolData = dict() + poolData["state"] = data[0] + poolData["nominatorsCount"] = data[1] + poolData["stakeAmountSent"] = ng2g(data[2]) + poolData["validatorAmount"] = ng2g(data[3]) + poolData["config"] = poolConfig + poolData["nominators"] = data[9] + poolData["withdrawRequests"] = data[10] + poolData["stakeAt"] = data[11] + poolData["savedValidatorSetHash"] = data[12] + poolData["validatorSetChangesCount"] = data[13] + poolData["validatorSetChangeTime"] = data[14] + poolData["stakeHeldFor"] = data[15] + return poolData +#end define diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 5e22297d..006c106d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -712,9 +712,6 @@ def ActivateWallet(local, ton, args): ton.WalletsCheck() else: wallet = ton.GetLocalWallet(walletName) - if not os.path.isfile(wallet.bocFilePath): - local.add_log("Wallet {walletName} already activated".format(walletName=walletName), "warning") - return ton.ActivateWallet(wallet) color_print("ActivateWallet - {green}OK{endc}") #end define @@ -734,31 +731,6 @@ def PrintWalletsList(ton, args): print_table(table) #end define -def ImportWalletFromFile(local, ton, args): - try: - filePath = args[0] - except: - color_print("{red}Bad args. Usage:{endc} iw ") - return - if (".addr" in filePath): - filePath = filePath.replace(".addr", '') - if (".pk" in filePath): - filePath = filePath.replace(".pk", '') - if os.path.isfile(filePath + ".addr") == False: - local.add_log("ImportWalletFromFile error: Address file not found: " + filePath, "error") - return - if os.path.isfile(filePath + ".pk") == False: - local.add_log("ImportWalletFromFile error: Private key not found: " + filePath, "error") - return - if '/' in filePath: - walletName = filePath[filePath.rfind('/')+1:] - else: - walletName = filePath - copyfile(filePath + ".addr", ton.walletsDir + walletName + ".addr") - copyfile(filePath + ".pk", ton.walletsDir + walletName + ".pk") - color_print("ImportWalletFromFile - {green}OK{endc}") -#end define - def ImportWallet(ton, args): try: addr = args[0] diff --git a/setup.py b/setup.py index b1d3088f..21363e7d 100644 --- a/setup.py +++ b/setup.py @@ -23,6 +23,7 @@ ], package_data={ 'mytoninstaller.scripts': ['*.sh'], + 'mytoncore.contracts' :['single-nominator-pool/*'], 'mytonctrl': [ 'resources/*', 'scripts/*', From 5866bb17e3a33c295ce03df87170b2974d82f619 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:38:08 +0300 Subject: [PATCH 069/236] debug CalculateLoanAmount --- mytoncore.py | 9 +++++++++ mytonctrl.py | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/mytoncore.py b/mytoncore.py index 58de8b6b..49a03299 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3833,6 +3833,7 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): ["num", max_loan*10**9], ["num", max_interest], ] + print(f"CalculateLoanAmount data: {data}") url = "http://127.0.0.1:8801/runGetMethod" res = requests.post(url, json=data) @@ -3843,6 +3844,14 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): result = res_data.get("result").get("stack").pop().pop() return result #end define + + def CalculateLoanAmount_test(): + min_loan = local.db.get("min_loan", 41000) + max_loan = local.db.get("max_loan", 43000) + max_interest_percent = local.db.get("max_interest_percent", 1.5) + max_interest = int(max_interest_percent/100*16777216) + return self.CalculateLoanAmount(min_loan, max_loan, max_interest) + #end define def WaitLoan(self, controllerAddr): local.add_log("start WaitLoan function", "debug") diff --git a/mytonctrl.py b/mytonctrl.py index 87c47567..dedfbbc1 100755 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -83,6 +83,8 @@ def Init(argv): console.AddItem("stop_and_withdraw_controller", StopAndWithdrawController, local.translate("_")) console.AddItem("add_controller", AddController, local.translate("_")) console.AddItem("check_liquid_pool", CheckLiquidPool, local.translate("_")) + console.AddItem("test_calculate_loan_amount", CalculateLoanAmount_test, local.translate("_")) + # Process input parameters @@ -1364,6 +1366,11 @@ def CheckLiquidPool(args): color_print("CheckLiquidPool - {green}OK{endc}") #end define +def CalculateLoanAmount_test(args): + t = ton.CalculateLoanAmount_test() + print(t) +#end define + ### ### Start of the program From 56a1039a7b377ecaec3a76507362d6cfb3ed87a4 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 25 Jan 2024 16:47:01 +0300 Subject: [PATCH 070/236] debug CalculateLoanAmount --- mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore.py b/mytoncore.py index 49a03299..abf8fd32 100755 --- a/mytoncore.py +++ b/mytoncore.py @@ -3845,7 +3845,7 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): return result #end define - def CalculateLoanAmount_test(): + def CalculateLoanAmount_test(self): min_loan = local.db.get("min_loan", 41000) max_loan = local.db.get("max_loan", 43000) max_interest_percent = local.db.get("max_interest_percent", 1.5) From 80374904982b225e29bc26c0276ae3dd0511c907 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:27:35 +0300 Subject: [PATCH 071/236] bugfix --- mytoninstaller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoninstaller.py b/mytoninstaller.py index 6b5916c9..1499bd7b 100644 --- a/mytoninstaller.py +++ b/mytoninstaller.py @@ -196,8 +196,8 @@ def Event(name): DangerousRecoveryValidatorConfigFile() if name == "enableJR": EnableJsonRpc() - if name == "enablePT": - EnablePytonv3() + if name == "enableTHA": + EnableTonHttpApi() if name == "clc": ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] From 9c574c364226064a8a5244389a374b3448e3b274 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:33:12 +0300 Subject: [PATCH 072/236] bugfix --- scripts/ton_http_api_installer.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ton_http_api_installer.sh b/scripts/ton_http_api_installer.sh index b27ef02a..9327f870 100644 --- a/scripts/ton_http_api_installer.sh +++ b/scripts/ton_http_api_installer.sh @@ -31,7 +31,7 @@ echo -e "${COLOR}[3/4]${ENDC} Add to startup" venv_ton_http_api="${venv_path}/bin/ton-http-api" tonlib_path="/usr/bin/ton/tonlib/libtonlibjson.so" ls_config="/usr/bin/ton/localhost.config.json" -cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import Add2Systemd; Add2Systemd(name='ton_http_api', user='${user}', start='${venv_ton_http_api} --host 127.0.0.1 --port 8801 --liteserver-config ${ls_config} --cdll-path ${tonlib_path} --tonlib-keystore /tmp/tonlib_keystore/')" +cmd="from sys import path; path.append('/usr/src/mytonctrl/'); from mypylib.mypylib import add2systemd; add2systemd(name='ton_http_api', user='${user}', start='${venv_ton_http_api} --host 127.0.0.1 --port 8801 --liteserver-config ${ls_config} --cdll-path ${tonlib_path} --tonlib-keystore /tmp/tonlib_keystore/')" python3 -c "${cmd}" systemctl restart ton_http_api From 41d522d6a28d2939ce2d27353acc741f37ff6d10 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 25 Jan 2024 17:39:54 +0300 Subject: [PATCH 073/236] bugfix --- mytoninstaller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoninstaller.py b/mytoninstaller.py index 1499bd7b..f3726178 100644 --- a/mytoninstaller.py +++ b/mytoninstaller.py @@ -198,7 +198,7 @@ def Event(name): EnableJsonRpc() if name == "enableTHA": EnableTonHttpApi() - if name == "clc": + if name in ["clc", "clcl"]: ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] initBlock = b642dict(initBlock_b64) From 3f85b155b090bc9b9fac5cae99f9217ff0c0ff21 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 26 Jan 2024 21:14:46 +0300 Subject: [PATCH 074/236] update_validator_set bugfix --- mytoncore/mytoncore.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 10fa55a9..f8a8bcfd 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1495,12 +1495,11 @@ def PoolsUpdateValidatorSet(self): wallet = self.GetValidatorWallet() pools = self.GetPools() for pool in pools: - self.PoolUpdateValidatorSet(pool, wallet) + self.PoolUpdateValidatorSet(pool.addrB64, wallet) #end define - def PoolUpdateValidatorSet(self, pool, wallet): + def PoolUpdateValidatorSet(self, poolAddr, wallet): self.local.add_log("start PoolUpdateValidatorSet function", "debug") - poolAddr = pool.addrB64 poolData = self.GetPoolData(poolAddr) if poolData is None: return @@ -1522,8 +1521,8 @@ def PoolUpdateValidatorSet(self, pool, wallet): timeNow - poolData["validatorSetChangeTime"] > poolData["stakeHeldFor"] + 60): self.PoolRecoverStake(poolAddr) poolData = self.GetPoolData(poolAddr) - if (poolData["state"] == 0 and self.HasPoolWithdrawRequests(pool)): - self.PoolWithdrawRequests(pool, wallet) + if (poolData["state"] == 0 and self.HasPoolWithdrawRequests(poolAddr)): + self.PoolWithdrawRequests(poolAddr, wallet) poolData = self.GetPoolData(poolAddr) if (poolData["state"] == 0 and poolAddr in pendingWithdraws): self.HandlePendingWithdraw(pendingWithdraws, poolAddr) @@ -1541,10 +1540,10 @@ def PoolProcessUpdateValidatorSet(self, poolAddr, wallet): self.local.add_log("PoolProcessUpdateValidatorSet completed") #end define - def PoolWithdrawRequests(self, pool, wallet): + def PoolWithdrawRequests(self, poolAddr, wallet): self.local.add_log("start PoolWithdrawRequests function", "debug") resultFilePath = self.PoolProcessWihtdrawRequests() - resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 10) + resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, poolAddr, 10) self.SendFile(resultFilePath, wallet) self.local.add_log("PoolWithdrawRequests completed") #end define @@ -1559,8 +1558,8 @@ def PoolProcessWihtdrawRequests(self): return resultFilePath #end define - def HasPoolWithdrawRequests(self, pool): - cmd = f"runmethodfull {pool.addrB64} has_withdraw_requests" + def HasPoolWithdrawRequests(self, poolAddr): + cmd = f"runmethodfull {poolAddr} has_withdraw_requests" result = self.liteClient.Run(cmd) buff = self.Result2List(result) data = int(buff[0]) From 01a36ed7230cad9177055a1a0171499d3ec60c13 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 28 Jan 2024 12:49:06 +0300 Subject: [PATCH 075/236] update for single-nominator --- .../contracts/single-nominator-pool/init.fif | 2 +- .../single-nominator-pool/recover-stake.fif | 17 ++ .../single-nominator.tlb | 94 +++++++ .../validator-elect-signed.fif | 44 ++++ .../validator-withdraw.fif | 18 ++ .../single-nominator-pool/withdraw.fif | 16 -- mytoncore/modules/single-nominator.py | 239 ------------------ mytoncore/mytoncore.py | 67 ++++- mytonctrl/mytonctrl.py | 84 ++++-- mytonctrl/scripts/validator-desync.sh | 14 + 10 files changed, 300 insertions(+), 295 deletions(-) create mode 100644 mytoncore/contracts/single-nominator-pool/recover-stake.fif create mode 100644 mytoncore/contracts/single-nominator-pool/single-nominator.tlb create mode 100644 mytoncore/contracts/single-nominator-pool/validator-elect-signed.fif create mode 100644 mytoncore/contracts/single-nominator-pool/validator-withdraw.fif delete mode 100755 mytoncore/contracts/single-nominator-pool/withdraw.fif delete mode 100644 mytoncore/modules/single-nominator.py create mode 100644 mytonctrl/scripts/validator-desync.sh diff --git a/mytoncore/contracts/single-nominator-pool/init.fif b/mytoncore/contracts/single-nominator-pool/init.fif index 69624e9d..d102c8bb 100755 --- a/mytoncore/contracts/single-nominator-pool/init.fif +++ b/mytoncore/contracts/single-nominator-pool/init.fif @@ -28,7 +28,7 @@ B>boc =: new-code-boc 2 boc+>B dup ."StateInit: " B>base64 type cr cr dup ."HEX: " Bx. cr -file-base +"-init.boc" tuck B>file +file-base +"-query.boc" tuck B>file ."(Saved single nominator pool init into " type .")" cr cr init-boc hashu wc swap 2dup 2=: dest-addr diff --git a/mytoncore/contracts/single-nominator-pool/recover-stake.fif b/mytoncore/contracts/single-nominator-pool/recover-stake.fif new file mode 100644 index 00000000..871b3855 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/recover-stake.fif @@ -0,0 +1,17 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates the message body to be sent from a validator controlling smart contract (wallet) to recover its share of unfrozen stakes and bonuses." cr + ."The result is saved into (`recover-query.boc` by default) and output in hexadecimal form, to be sent later as the body of a message from the wallet to elections smart contract, along with a small value (say, one Gram) to cover forwarding and processing fees" cr 1 halt +} : usage + +$# dup 0 < swap 1 > or ' usage if +def? $1 { @' $1 } { "recover-query.boc" } cond constant output_fname +now constant query_id +."query_id for stake recovery message is set to " query_id . cr + + +cr ."Message body is " dup B output_fname tuck B>file ."Saved to file " type cr diff --git a/mytoncore/contracts/single-nominator-pool/single-nominator.tlb b/mytoncore/contracts/single-nominator-pool/single-nominator.tlb new file mode 100644 index 00000000..d1470a01 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/single-nominator.tlb @@ -0,0 +1,94 @@ +bit$_ (## 1) = Bit; +bool_false$0 = Bool; +bool_true$1 = Bool; + +left$0 {X:Type} {Y:Type} value:X = Either X Y; +right$1 {X:Type} {Y:Type} value:Y = Either X Y; + +// + +hm_edge#_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n) + {n = (~m) + l} node:(HashmapNode m X) = Hashmap n X; + +hmn_leaf#_ {X:Type} value:X = HashmapNode 0 X; +hmn_fork#_ {n:#} {X:Type} left:^(Hashmap n X) + right:^(Hashmap n X) = HashmapNode (n + 1) X; + +hml_short$0 {m:#} {n:#} len:(Unary ~n) {n <= m} s:(n * Bit) = HmLabel ~n m; +hml_long$10 {m:#} n:(#<= m) s:(n * Bit) = HmLabel ~n m; +hml_same$11 {m:#} v:Bit n:(#<= m) = HmLabel ~n m; + +unary_zero$0 = Unary ~0; +unary_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1); + +hme_empty$0 {n:#} {X:Type} = HashmapE n X; +hme_root$1 {n:#} {X:Type} root:^(Hashmap n X) = HashmapE n X; + +// + +nothing$0 {X:Type} = Maybe X; +just$1 {X:Type} value:X = Maybe X; + +anycast_info$_ depth:(#<= 30) { depth >= 1 } + rewrite_pfx:(bits depth) = Anycast; + +addr_std$10 anycast:(Maybe Anycast) + workchain_id:int8 address:bits256 = MsgAddressInt; +_ _:MsgAddressInt = MsgAddress; + +_ address:MsgAddress = Addr; + +// + +var_uint$_ {n:#} len:(#< n) value:(uint (len * 8)) + = VarUInteger n; +var_int$_ {n:#} len:(#< n) value:(int (len * 8)) + = VarInteger n; +nanograms$_ amount:(VarUInteger 16) = Grams; + +_ grams:Grams = Coins; + +// + +extra_currencies$_ dict:(HashmapE 32 (VarUInteger 32)) + = ExtraCurrencyCollection; +currencies$_ grams:Grams other:ExtraCurrencyCollection + = CurrencyCollection; + +// + +tick_tock$_ tick:Bool tock:Bool = TickTock; + +_ split_depth:(Maybe (## 5)) special:(Maybe TickTock) + code:(Maybe ^Cell) data:(Maybe ^Cell) + library:(Maybe ^Cell) = StateInit; + +int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + src:MsgAddressInt dest:MsgAddressInt + value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams + created_lt:uint64 created_at:uint32 = CommonMsgInfo; + +message$_ {X:Type} info:CommonMsgInfo + init:(Maybe (Either StateInit ^StateInit)) + body:(Either X ^X) = Message X; + +_ (Message Any) = MessageAny; + +// + +storage#_ owner_address:MsgAddress validator_address:MsgAddress = Storage; + +// owner ops +withdraw#1000 query_id:uint64 amount:Coins = InternalMsgBody; +change_validator_address#1001 query_id:uint64 new_validator_address:MsgAddress = InternalMsgBody; +send_raw_msg#7702 query_id:uint64 mode:uint8 msg:^MessageAny = InternalMsgBody; +upgrade#9903 query_id:uint64 code:^Cell = InternalMsgBody; + +// elector ops +new_stakedata#_ validator_pubkey:bits256 stake_at:uint32 max_factor:uint32 andl_addr:bits256 signature:^bits512 = NewStakeData; + +// 2 opcodes respond for 2 InternalMsgBody schemes +// so to avoid errors - here is OutMsgBody +new_stake_to_validator#4e73744b query_id:uint64 stake_data:NewStakeData = OutMsgBody; +new_stake#4e73744b query_id:uint64 stake_amount:Coins new_stake_msg:NewStakeData = InternalMsgBody; +recover_stake#47657424 query_id:uint64 = InternalMsgBody; diff --git a/mytoncore/contracts/single-nominator-pool/validator-elect-signed.fif b/mytoncore/contracts/single-nominator-pool/validator-elect-signed.fif new file mode 100644 index 00000000..a7c42da5 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/validator-elect-signed.fif @@ -0,0 +1,44 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." " cr + ."Creates a message body for participating in validator elections starting at on behalf of smart-contract with address (prefix with '@' to load address from file) and hexadecimal adnl address (empty string or '0' for none)." cr + ." is the main public key of the future validator (as a Base64 string), and is the signature of the previously created validator request by that key (also Base64)" cr + ."The result is saved into (`validator-query.boc` by default) and output in hexadecimal form, to be sent later as the body of a message from to elections smart contract, along with the desired stake" cr 1 halt +} : usage + +$# dup 8 < swap 8 > or ' usage if +$1 true parse-load-address drop swap 1+ abort"only masterchain smartcontracts may participate in validator elections" +constant src_addr +$2 (number) 1 <> { 0 } if dup 0<= abort" must be a positive integer" +constant elect_time +$3 (number) dup 0= abort" must be a real number 1..100" +1 = { 16 << } { 16 < or abort" must be a real number 1..100" +constant max_factor +$4 dup $len 1 > { parse-adnl-address } { drop 0 } cond constant adnl_addr +$5 base64>B dup Blen 36 <> abort"validator Ed25519 public key must be exactly 36 bytes long" + 32 B>u@+ 0xC6B41348 <> abort"invalid Ed25519 public key: unknown magic number" + constant pubkey +$6 base64>B dup Blen 64 <> abort"validator Ed25519 signature must be exactly 64 bytes long" +constant signature +$7 constant output_fname +$8 $>GR =: amount + +."Creating a request to participate in validator elections at time " elect_time . +."from smart contract " -1 src_addr 2dup 1 .Addr ." = " .addr +." with maximal stake factor with respect to the minimal stake " max_factor ._ +."/65536 and validator ADNL address " adnl_addr 64x. cr + +B{654c5074} elect_time 32 u>B B+ max_factor 32 u>B B+ src_addr 256 u>B B+ adnl_addr 256 u>B B+ +."String to sign is: " dup Bx. cr constant to_sign + +to_sign signature pubkey ed25519_chksign not abort"Ed25519 signature is invalid" +."Provided a valid Ed25519 signature " signature Bx. ." with validator public key " pubkey Bx. cr +now dup constant query_id ."query_id set to " . cr + + ref, b> +cr ."Message body is " dup B output_fname tuck B>file ."Saved to file " type cr diff --git a/mytoncore/contracts/single-nominator-pool/validator-withdraw.fif b/mytoncore/contracts/single-nominator-pool/validator-withdraw.fif new file mode 100644 index 00000000..387f4bc1 --- /dev/null +++ b/mytoncore/contracts/single-nominator-pool/validator-withdraw.fif @@ -0,0 +1,18 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."" cr + ."" cr 1 halt +} : usage + +$# dup 1 < swap 2 > or ' usage if +$1 $>GR =: amount +def? $2 { @' $2 } { "validator-withdraw-query.boc" } cond constant output_fname +now constant query_id +."query_id for stake recovery message is set to " query_id . ."amount=" amount .GR cr + + +cr ."Message body is " dup B output_fname tuck B>file ."Saved to file " type cr diff --git a/mytoncore/contracts/single-nominator-pool/withdraw.fif b/mytoncore/contracts/single-nominator-pool/withdraw.fif deleted file mode 100755 index 96ccfe8e..00000000 --- a/mytoncore/contracts/single-nominator-pool/withdraw.fif +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env fift -s -"TonUtil.fif" include -"Asm.fif" include - -{ ."usage: " @' $0 type ." " cr - ."Creates a message body to withdraw from a single-nominator pool." cr 1 halt -} : usage -$# 1 = { } { usage } cond - -$1 $>GR =: amount - - =: body_boc -body_boc B -"withdraw.boc" tuck B>file -."(Saved witdhraw query to file to file " type .")" cr diff --git a/mytoncore/modules/single-nominator.py b/mytoncore/modules/single-nominator.py deleted file mode 100644 index 84528c12..00000000 --- a/mytoncore/modules/single-nominator.py +++ /dev/null @@ -1,239 +0,0 @@ -import pkg_resources - -def create_single_nominator_pool(self, pool_name, owner_address): - self.local.add_log("start create_single_nominator_pool function", "debug") - - file_path = self.poolsDir + pool_name - if os.path.isfile(file_path + ".addr"): - self.local.add_log("create_single_nominator_pool warning: Pool already exists: " + file_path, "warning") - return - #end if - - fift_script = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/init.fif') - validator_wallet = self.GetValidatorWallet() - args = [fift_script, owner_address, validator_wallet.addrB64, file_path] - result = self.fift.Run(args) - if "Saved single nominator pool" not in result: - raise Exception("create_single_nominator_pool error: " + result) - #end if - - pools = self.get_single_pools() - new_pool = self.get_single_local_pool(pool_name) - for pool in pools: - if pool.name != new_pool.name and pool.addrB64 == new_pool.addrB64: - new_pool.Delete() - raise Exception("create_single_nominator_pool error: Pool with the same parameters already exists.") - #end for -#end define - -def activate_pool(self, pool, ex=True): - self.local.add_log("start activate_pool function", "debug") - for i in range(10): - time.sleep(3) - account = self.GetAccount(pool.addrB64) - if account.balance > 0: - self.SendFile(pool.bocFilePath, pool, timeout=False) - return - if ex: - raise Exception("activate_pool error: time out") -#end define - -def DepositToPool(self, poolAddr, amount): - wallet = self.GetValidatorWallet() - 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) - resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, amount) - self.SendFile(resultFilePath, wallet) -#end define - -def WithdrawFromPool(self, poolAddr, amount): - poolData = self.GetPoolData(poolAddr) - if poolData["state"] == 0: - self.WithdrawFromPoolProcess(poolAddr, amount) - else: - self.PendWithdrawFromPool(poolAddr, amount) -#end define - -def WithdrawFromPoolProcess(self, poolAddr, amount): - self.local.add_log("start WithdrawFromPoolProcess function", "debug") - wallet = self.GetValidatorWallet() - 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) - resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, 1.35) - self.SendFile(resultFilePath, wallet) -#end define - -def PendWithdrawFromPool(self, poolAddr, amount): - self.local.add_log("start PendWithdrawFromPool function", "debug") - pendingWithdraws = self.GetPendingWithdraws() - pendingWithdraws[poolAddr] = amount - self.local.save() -#end define - -def HandlePendingWithdraw(self, pendingWithdraws, poolAddr): - amount = pendingWithdraws.get(poolAddr) - self.WithdrawFromPoolProcess(poolAddr, amount) - pendingWithdraws.pop(poolAddr) -#end define - -def GetPendingWithdraws(self): - bname = "pendingWithdraws" - pendingWithdraws = self.local.db.get(bname) - if pendingWithdraws is None: - pendingWithdraws = dict() - self.local.db[bname] = pendingWithdraws - return pendingWithdraws -#end define - -def SignElectionRequestWithPoolWithValidator(self, pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): - 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] - result = self.fift.Run(args) - pubkey = parse(result, "validator public key ", '\n') - fileName = parse(result, "Saved to file ", '\n') - return pubkey, fileName -#end define - -def PoolProcessRecoverStake(self): - 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] - result = self.fift.Run(args) - resultFilePath = parse(result, "Saved to file ", '\n') - 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 get_single_local_pool(self, pool_name): - self.local.add_log("start get_single_local_pool function", "debug") - if pool_name is None: - return None - filePath = self.poolsDir + pool_name - - # Create pool object - pool = Pool(pool_name, filePath) - if os.path.isfile(pool.addrFilePath) == False: - raise Exception(f"get_single_local_pool error: Address file not found: {pool.addrFilePath}") - #end if - - self.AddrFile2Object(pool) - return pool -#end define - -def GetPoolsNameList(self): - self.local.add_log("start GetPoolsNameList function", "debug") - poolsNameList = list() - for fileName in os.listdir(self.poolsDir): - if fileName.endswith(".addr"): - fileName = fileName[:fileName.rfind('.')] - poolsNameList.append(fileName) - poolsNameList.sort() - return poolsNameList -#end define - -def get_single_pools(self): - self.local.add_log("start get_single_pools function", "debug") - pools = list() - poolsNameList = self.GetPoolsNameList() - for pool_name in poolsNameList: - pool = self.get_single_local_pool(pool_name) - pools.append(pool) - return pools -#end define - -def GetPool(self, mode): - pools = self.get_single_pools() - for pool in pools: - if mode == "stake" and self.IsPoolReadyToStake(pool.addrB64): - return pool - if mode == "vote" and self.IsPoolReadyToVote(pool.addrB64): - return pool - raise Exception("Validator pool not found or not ready") -#end define - -def GetPoolLastSentStakeTime(self, addrB64): - poolData = self.GetPoolData(addrB64) - return poolData["stakeAt"] -#end define - -def IsPoolReadyToStake(self, addrB64): - now = get_timestamp() - config15 = self.GetConfig15() - lastSentStakeTime = self.GetPoolLastSentStakeTime(addrB64) - stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] - result = lastSentStakeTime + stakeFreezeDelay < now - print(f"{addrB64}: {result}. {lastSentStakeTime}, {stakeFreezeDelay}, {now}") - return result -#end define - -def IsPoolReadyToVote(self, addrB64): - vwl = self.GetValidatorsWalletsList() - result = addrB64 in vwl - return result -#end define - -def GetPoolData(self, addrB64): - self.local.add_log("start GetPoolData function", "debug") - cmd = f"runmethodfull {addrB64} get_pool_data" - result = self.liteClient.Run(cmd) - data = self.Result2List(result) - if data is None: - return - poolConfig = dict() - poolConfig["validatorAddress"] = data[4] - poolConfig["validatorRewardShare"] = data[5] - poolConfig["validatorRewardSharePercent"] = data[5] / 100 - poolConfig["maxNominatorsCount"] = data[6] - poolConfig["minValidatorStake"] = ng2g(data[7]) - poolConfig["minNominatorStake"] = ng2g(data[8]) - poolData = dict() - poolData["state"] = data[0] - poolData["nominatorsCount"] = data[1] - poolData["stakeAmountSent"] = ng2g(data[2]) - poolData["validatorAmount"] = ng2g(data[3]) - poolData["config"] = poolConfig - poolData["nominators"] = data[9] - poolData["withdrawRequests"] = data[10] - poolData["stakeAt"] = data[11] - poolData["savedValidatorSetHash"] = data[12] - poolData["validatorSetChangesCount"] = data[13] - poolData["validatorSetChangeTime"] = data[14] - poolData["stakeHeldFor"] = data[15] - return poolData -#end define diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index f8a8bcfd..3753ae76 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -7,6 +7,7 @@ import struct import psutil import subprocess +import pkg_resources from fastcrc import crc16 from mytoncore.utils import xhex2hex, ng2g @@ -500,7 +501,7 @@ def WalletVersion2Wallet(self, wallet): account = self.GetAccount(wallet.addrB64) version = walletsVersionList.get(wallet.addrB64) if version is None: - version = self.GetWalletVersionFromHash(account.codeHash) + version = self.GetVersionFromCodeHash(account.codeHash) if version is None: self.local.add_log("Wallet version not found: " + wallet.addrB64, "warning") return @@ -516,8 +517,8 @@ def SetWalletVersion(self, addrB64, version): self.local.save() #end define - def GetWalletVersionFromHash(self, inputHash): - self.local.add_log("start GetWalletVersionFromHash function", "debug") + def GetVersionFromCodeHash(self, inputHash): + self.local.add_log("start GetVersionFromCodeHash function", "debug") arr = dict() arr["v1r1"] = "d670136510daff4fee1889b8872c4c1e89872ffa1fe58a23a5f5d99cef8edf32" arr["v1r2"] = "2705a31a7ac162295c8aed0761cc6e031ab65521dd7b4a14631099e02de99e18" @@ -528,6 +529,8 @@ def GetWalletVersionFromHash(self, inputHash): arr["v3r2"] = "8a6d73bdd8704894f17d8c76ce6139034b8a51b1802907ca36283417798a219b" arr["v4"] = "7ae380664c513769eaa5c94f9cd5767356e3f7676163baab66a4b73d5edab0e5" arr["hv1"] = "fc8e48ed7f9654ba76757f52cc6031b2214c02fab9e429ffa0340f5575f9f29c" + arr["pool"] = "399838da9489139680e90fd237382e96ba771fdf6ea27eb7d513965b355038b4" + arr["spool"] = "fc2ae44bcaedfa357d0091769aabbac824e1c28f14cc180c0b52a57d83d29054" for version, hash in arr.items(): if hash == inputHash: return version @@ -1143,11 +1146,12 @@ def SignElectionRequestWithValidator(self, wallet, startWorkTime, adnlAddr, vali return pubkey, fileName #end define - def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): + def SignBocWithWallet(self, wallet, boc_path, dest, coins, **kwargs): self.local.add_log("start SignBocWithWallet function", "debug") flags = kwargs.get("flags", list()) subwalletDefault = 698983191 + wallet.workchain # 0x29A9A317 + workchain subwallet = kwargs.get("subwallet", subwalletDefault) + boc_mode = kwargs.get("boc_mode", "--body") # Balance checking account = self.GetAccount(wallet.addrB64) @@ -1159,7 +1163,7 @@ def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): destAccount = self.GetAccount(dest) bounceable = self.IsBounceableAddrB64(dest) if bounceable == False and destAccount.status == "active": - flags += ["-b"] + flags += ["--force-bounce"] text = "Find non-bounceable flag, but destination account already active. Using bounceable flag" self.local.AddLog(text, "warning") elif "-n" not in flags and bounceable == True and destAccount.status != "active": @@ -1167,21 +1171,21 @@ def SignBocWithWallet(self, wallet, bocPath, dest, coins, **kwargs): #end if seqno = self.GetSeqno(wallet) - resultFilePath = self.tempDir + self.nodeName + wallet.name + "_wallet-query" + result_file_path = self.tempDir + self.nodeName + wallet.name + "_wallet-query" if "v1" in wallet.version: - fiftScript = "wallet.fif" - args = [fiftScript, wallet.path, dest, seqno, coins, "-B", bocPath, resultFilePath] + fift_script = "wallet.fif" + args = [fift_script, wallet.path, dest, seqno, coins, boc_mode, boc_path, result_file_path] elif "v2" in wallet.version: - fiftScript = "wallet-v2.fif" - args = [fiftScript, wallet.path, dest, seqno, coins, "-B", bocPath, resultFilePath] + fift_script = "wallet-v2.fif" + args = [fift_script, wallet.path, dest, seqno, coins, boc_mode, boc_path, result_file_path] elif "v3" in wallet.version: - fiftScript = "wallet-v3.fif" - args = [fiftScript, wallet.path, dest, subwallet, seqno, coins, "-B", bocPath, resultFilePath] + fift_script = "wallet-v3.fif" + args = [fift_script, wallet.path, dest, subwallet, seqno, coins, boc_mode, boc_path, result_file_path] if flags: args += flags result = self.fift.Run(args) - resultFilePath = parse(result, "Saved to file ", ")") - return resultFilePath + result_file_path = parse(result, "Saved to file ", ")") + return result_file_path #end define def SendFile(self, filePath, wallet=None, **kwargs): @@ -3521,6 +3525,41 @@ def GetPoolData(self, addrB64): return poolData #end define + def create_single_pool(self, pool_name, owner_address): + self.local.add_log("start create_single_pool function", "debug") + + file_path = self.poolsDir + pool_name + if os.path.isfile(file_path + ".addr"): + self.local.add_log("create_single_pool warning: Pool already exists: " + file_path, "warning") + return + #end if + + fift_script = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/init.fif') + code_boc = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/single-nominator-code.hex') + validator_wallet = self.GetValidatorWallet() + args = [fift_script, code_boc, owner_address, validator_wallet.addrB64, file_path] + result = self.fift.Run(args) + if "Saved single nominator pool" not in result: + raise Exception("create_single_pool error: " + result) + #end if + + pools = self.GetPools() + new_pool = self.GetLocalPool(pool_name) + for pool in pools: + if pool.name != new_pool.name and pool.addrB64 == new_pool.addrB64: + new_pool.Delete() + raise Exception("create_single_pool error: Pool with the same parameters already exists.") + #end for + #end define + + def activate_single_pool(self, pool, ex=True): + self.local.add_log("start activate_single_pool function", "debug") + boc_mode = "--with-init" + validator_wallet = self.GetValidatorWallet() + resultFilePath = self.SignBocWithWallet(validator_wallet, pool.bocFilePath, pool.addrB64_init, 1, boc_mode=boc_mode) + self.SendFile(resultFilePath, validator_wallet) + #end define + def GetNetworkName(self): data = self.local.read_db(self.liteClient.configPath) mainnet_init_block_root_hash = "YRkrcmZMvLBvjanwKCyL3w4oceGPtFfgx8ym1QKCK/4=" diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 006c106d..98559f88 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -134,6 +134,9 @@ def inject_globals(func): 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("new_single_pool", inject_globals(new_single_pool), local.translate("new_single_pool_cmd")) + console.AddItem("activate_single_pool", inject_globals(activate_single_pool), local.translate("activate_single_pool_cmd")) + # console.AddItem("pt", inject_globals(PrintTest), "PrintTest") # console.AddItem("sl", inject_globals(sl), "sl") console.AddItem("cleanup", inject_globals(cleanup_validator_db), local.translate("cleanup_cmd")) @@ -787,13 +790,18 @@ def ViewAccountStatus(ton, args): return addrB64 = ton.GetDestinationAddr(addrB64) account = ton.GetAccount(addrB64) - version = ton.GetWalletVersionFromHash(account.codeHash) + version = ton.GetVersionFromCodeHash(account.codeHash) statusTable = list() - statusTable += [["Address", "Status", "Version", "Balance"]] - statusTable += [[addrB64, account.status, version, account.balance]] + statusTable += [["Address", "Status", "Balance", "Version"]] + statusTable += [[addrB64, account.status, account.balance, version]] + codeHashTable = list() + codeHashTable += [["Code hash"]] + codeHashTable += [[account.codeHash]] historyTable = GetHistoryTable(ton, addrB64, 10) print_table(statusTable) print() + print_table(codeHashTable) + print() print_table(historyTable) #end define @@ -1316,7 +1324,7 @@ def NewRestrictedWallet(ton, args): def NewPool(ton, args): try: - poolName = args[0] + pool_name = args[0] validatorRewardSharePercent = float(args[1]) maxNominatorsCount = int(args[2]) minValidatorStake = int(args[3]) @@ -1324,19 +1332,19 @@ def NewPool(ton, args): except: color_print("{red}Bad args. Usage:{endc} new_pool ") return - ton.CreatePool(poolName, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake) + ton.CreatePool(pool_name, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake) color_print("NewPool - {green}OK{endc}") #end define def ActivatePool(local, ton, args): try: - poolName = args[0] + pool_name = args[0] except: color_print("{red}Bad args. Usage:{endc} activate_pool ") return - pool = ton.GetLocalPool(poolName) + pool = ton.GetLocalPool(pool_name) if not os.path.isfile(pool.bocFilePath): - local.add_log(f"Pool {poolName} already activated", "warning") + local.add_log(f"Pool {pool_name} already activated", "warning") return ton.ActivatePool(pool) color_print("ActivatePool - {green}OK{endc}") @@ -1344,7 +1352,7 @@ def ActivatePool(local, ton, args): def PrintPoolsList(ton, args): table = list() - table += [["Name", "Status", "Balance", "Address"]] + table += [["Name", "Status", "Balance", "Version", "Address"]] data = ton.GetPools() if (data is None or len(data) == 0): print("No data") @@ -1353,69 +1361,95 @@ def PrintPoolsList(ton, args): account = ton.GetAccount(pool.addrB64) if account.status != "active": pool.addrB64 = pool.addrB64_init - table += [[pool.name, account.status, account.balance, pool.addrB64]] + version = ton.GetVersionFromCodeHash(account.codeHash) + table += [[pool.name, account.status, account.balance, version, pool.addrB64]] print_table(table) #end define def GetPoolData(ton, args): try: - poolName = args[0] + pool_name = args[0] except: color_print("{red}Bad args. Usage:{endc} get_pool_data ") return - if ton.IsAddr(poolName): - poolAddr = poolName + if ton.IsAddr(pool_name): + pool_addr = pool_name else: - pool = ton.GetLocalPool(poolName) - poolAddr = pool.addrB64 - poolData = ton.GetPoolData(poolAddr) - print(json.dumps(poolData, indent=4)) + pool = ton.GetLocalPool(pool_name) + pool_addr = pool.addrB64 + pool_data = ton.GetPoolData(pool_addr) + print(json.dumps(pool_data, indent=4)) #end define def DepositToPool(ton, args): try: - pollAddr = args[0] + poll_addr = args[0] amount = float(args[1]) except: color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") return - ton.DepositToPool(pollAddr, amount) + ton.DepositToPool(poll_addr, amount) color_print("DepositToPool - {green}OK{endc}") #end define def WithdrawFromPool(ton, args): try: - poolAddr = args[0] + pool_addr = args[0] amount = float(args[1]) except: color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") return - ton.WithdrawFromPool(poolAddr, amount) + ton.WithdrawFromPool(pool_addr, amount) color_print("WithdrawFromPool - {green}OK{endc}") #end define def DeletePool(ton, args): try: - poolName = args[0] + pool_name = args[0] except: color_print("{red}Bad args. Usage:{endc} delete_pool ") return - pool = ton.GetLocalPool(poolName) + pool = ton.GetLocalPool(pool_name) pool.Delete() color_print("DeletePool - {green}OK{endc}") #end define def UpdateValidatorSet(ton, args): try: - poolAddr = args[0] + pool_addr = args[0] except: color_print("{red}Bad args. Usage:{endc} update_validator_set ") return wallet = ton.GetValidatorWallet() - ton.PoolUpdateValidatorSet(poolAddr, wallet) + ton.PoolUpdateValidatorSet(pool_addr, wallet) color_print("UpdateValidatorSet - {green}OK{endc}") #end define +def new_single_pool(ton, args): + try: + pool_name = args[0] + owner_address = args[1] + except: + color_print("{red}Bad args. Usage:{endc} new_single_pool ") + return + ton.create_single_pool(pool_name, owner_address) + color_print("new_single_pool - {green}OK{endc}") +#end define + +def activate_single_pool(local, ton, args): + try: + pool_name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} activate_single_pool ") + return + pool = ton.get_local_single_pool(pool_name) + if not os.path.isfile(pool.bocFilePath): + local.add_log(f"Pool {pool_name} already activated", "warning") + return + ton.activate_single_pool(pool) + color_print("activate_single_pool - {green}OK{endc}") +#end define + ### ### Start of the program diff --git a/mytonctrl/scripts/validator-desync.sh b/mytonctrl/scripts/validator-desync.sh new file mode 100644 index 00000000..898f527f --- /dev/null +++ b/mytonctrl/scripts/validator-desync.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +stats=$(validator-console -c getstats) +unixtime=$(echo "$stats" | grep unixtime | awk '{print $2}') +mastertime=$(echo "$stats" | grep masterchainblocktime | awk '{print $2}') +if [ -z $mastertime ] +then + result="mastertime is None" +else + result=$(($unixtime-$mastertime)) +fi + +echo $result From 3a9c83c8f12a7fbd011b4f494d209b5db57f22b4 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 29 Jan 2024 22:46:32 +0700 Subject: [PATCH 076/236] fix file unclosing --- mytoncore/mytoncore.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 3753ae76..1f49a612 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -491,6 +491,7 @@ def AddrFile2Object(self, object): object.addrFull = f"{object.workchain}:{object.addr}" object.addrB64 = self.AddrFull2AddrB64(object.addrFull) object.addrB64_init = self.AddrFull2AddrB64(object.addrFull, bounceable=False) + file.close() #end define def WalletVersion2Wallet(self, wallet): From 6f68acc3f1bd7472f48602a4a0e7e44383e9bbe3 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 30 Jan 2024 00:12:36 +0700 Subject: [PATCH 077/236] fix get pool function name --- mytoncore/mytoncore.py | 2 +- mytonctrl/mytonctrl.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 1f49a612..79f01b7f 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3553,7 +3553,7 @@ def create_single_pool(self, pool_name, owner_address): #end for #end define - def activate_single_pool(self, pool, ex=True): + def activate_single_pool(self, pool): self.local.add_log("start activate_single_pool function", "debug") boc_mode = "--with-init" validator_wallet = self.GetValidatorWallet() diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 98559f88..8642bed8 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1442,7 +1442,7 @@ def activate_single_pool(local, ton, args): except: color_print("{red}Bad args. Usage:{endc} activate_single_pool ") return - pool = ton.get_local_single_pool(pool_name) + pool = ton.GetLocalPool(pool_name) if not os.path.isfile(pool.bocFilePath): local.add_log(f"Pool {pool_name} already activated", "warning") return From b77c4b351897e5d6690ff92c27c545f43e9f7f79 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:57:53 +0300 Subject: [PATCH 078/236] add import_pool and bugfix --- mytoncore/mytoncore.py | 45 ++++++++++++++++++++---------------- mytonctrl/mytonctrl.py | 22 +++++++++++++----- mytonctrl/progressbar.py | 1 + mytonctrl/scripts/etabar.py | 9 ++++++-- mytonctrl/scripts/upgrade.sh | 2 +- scripts/ton_installer.sh | 2 +- 6 files changed, 51 insertions(+), 30 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 79f01b7f..edc08eea 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1646,36 +1646,41 @@ def ActivateWallet(self, wallet): self.SendFile(wallet.bocFilePath, wallet, remove=False) #end define - def ImportWallet(self, addrB64, key): - workchain, addr, bounceable = self.ParseAddrB64(addrB64) + def ImportWallet(self, addr_b64, key): + addr_bytes = self.addr_b64_to_bytes(addr_b64) + pk_bytes = base64.b64decode(key) + wallet_name = self.GenerateWalletName() + wallet_path = self.walletsDir + wallet_name + with open(wallet_path + ".addr", 'wb') as file: + file.write(addr_bytes) + with open(wallet_path + ".pk", 'wb') as file: + file.write(pk_bytes) + return wallet_name + #end define + + def addr_b64_to_bytes(self, addr_b64): + workchain, addr, bounceable = self.ParseAddrB64(addr_b64) workchain_bytes = int.to_bytes(workchain, 4, "big", signed=True) addr_bytes = bytes.fromhex(addr) - key_bytes = base64.b64decode(key) - - walletName = self.GenerateWalletName() - walletPath = self.walletsDir + walletName - file = open(walletPath + ".addr", 'wb') - file.write(addr_bytes + workchain_bytes) - file.close() - - file = open(walletPath + ".pk", 'wb') - file.write(key_bytes) - file.close() - - return walletName + result = addr_bytes + workchain_bytes + return result #end define def ExportWallet(self, walletName): wallet = self.GetLocalWallet(walletName) - - file = open(wallet.privFilePath, 'rb') - data = file.read() - file.close() + with open(wallet.privFilePath, 'rb') as file: + data = file.read() key = base64.b64encode(data).decode("utf-8") - return wallet.addrB64, key #end define + def import_pool(self, pool_name, addr_b64): + addr_bytes = self.addr_b64_to_bytes(addr_b64) + pool_path = self.poolsDir + pool_name + with open(pool_path + ".addr", 'wb') as file: + file.write(addr_bytes) + #end define + def GetWalletsNameList(self): self.local.add_log("start GetWalletsNameList function", "debug") walletsNameList = list() diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 8642bed8..168a0ebc 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -136,6 +136,7 @@ def inject_globals(func): console.AddItem("new_single_pool", inject_globals(new_single_pool), local.translate("new_single_pool_cmd")) console.AddItem("activate_single_pool", inject_globals(activate_single_pool), local.translate("activate_single_pool_cmd")) + console.AddItem("import_pool", inject_globals(import_pool), local.translate("import_pool_cmd")) # console.AddItem("pt", inject_globals(PrintTest), "PrintTest") # console.AddItem("sl", inject_globals(sl), "sl") @@ -322,16 +323,14 @@ def run_benchmark(ton, args): benchmark_result_path = "/tmp/benchmark_result.json" run_args = ["python3", etabar_script_path, str(timeout), benchmark_script_path, benchmark_result_path] exit_code = run_as_root(run_args) + with open(benchmark_result_path, 'rt') as file: + text = file.read() if exit_code != 0: - color_print("Benchmark - {red}Error{endc}") + color_print("Benchmark - {red}Error:{endc} " + text) return #end if - with open(benchmark_result_path, 'rt') as file: - text = file.read() - data = Dict(json.loads(text)) - #end with - + data = Dict(json.loads(text)) table = list() table += [["Test type", "Read speed", "Write speed", "Read iops", "Write iops", "Random ops"]] table += [["Fio lite", data.lite.read_speed, data.lite.write_speed, data.lite.read_iops, data.lite.write_iops, None]] # RND-4K-QD64 @@ -1450,6 +1449,17 @@ def activate_single_pool(local, ton, args): color_print("activate_single_pool - {green}OK{endc}") #end define +def import_pool(ton, args): + try: + pool_name = args[0] + pool_addr = args[1] + except: + color_print("{red}Bad args. Usage:{endc} import_pool ") + return + ton.import_pool(pool_name, pool_addr) + color_print("import_pool - {green}OK{endc}") +#end define + ### ### Start of the program diff --git a/mytonctrl/progressbar.py b/mytonctrl/progressbar.py index a48b3641..a8776184 100644 --- a/mytonctrl/progressbar.py +++ b/mytonctrl/progressbar.py @@ -17,6 +17,7 @@ def __init__(self, **kwargs): self.indent_symbol = ' ' self.tty_height, self.tty_width = self.get_tty_size() + stdout.reconfigure(encoding="utf-8") #end define def run(self, func=None, *args, **kwargs): diff --git a/mytonctrl/scripts/etabar.py b/mytonctrl/scripts/etabar.py index b0508e46..57d7957c 100644 --- a/mytonctrl/scripts/etabar.py +++ b/mytonctrl/scripts/etabar.py @@ -13,10 +13,15 @@ args = ["bash", script] process = bar.run(run, args, stdin=PIPE, stdout=PIPE, stderr=PIPE, timeout=timeout) exit_code = -1 +output = "process is None" if process != None: exit_code = process.returncode stdout = process.stdout.decode("utf-8") stderr = process.stderr.decode("utf-8") - with open(result, 'wt') as file: - file.write(stdout) + if exit_code == 0: + output = stdout + else: + output = stderr +with open(result, 'wt') as file: + file.write(output) exit(exit_code) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index aed25870..57b98979 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -29,7 +29,7 @@ COLOR='\033[92m' ENDC='\033[0m' # Установить дополнительные зависимости -apt-get install -y libsecp256k1-dev libsodium-dev ninja-build +apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio # bugfix if the files are in the wrong place wget "https://ton-blockchain.github.io/global.config.json" -O global.config.json diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 1f7d62f9..df42cd11 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -50,7 +50,7 @@ if [ "$OSTYPE" == "linux-gnu" ]; then elif [ -f /etc/debian_version ]; then echo "Ubuntu/Debian Linux detected." apt-get update - apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev + apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev fio # Install ninja apt-get install -y ninja-build From ed95ef153434cd28cb9e71239bcbae09bd8ba1b7 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 30 Jan 2024 12:07:22 +0300 Subject: [PATCH 079/236] update single-nominator-code.fc --- .../single-nominator-pool/single-nominator-code.fc | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc b/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc index 48734ca4..aedb357d 100644 --- a/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc +++ b/mytoncore/contracts/single-nominator-pool/single-nominator-code.fc @@ -79,7 +79,17 @@ int check_new_stake_msg(slice cs) impure inline_ref; slice sender = cs~load_msg_addr(); int op = in_msg_body~load_uint(32); - int query_id = in_msg_body~load_uint(64); + int query_id = 0; ;; filled below + + ;; if just a message with comment "w" - means withdraw + if ( (op == 0) & (equal_slice_bits(in_msg_body, "w")) & (in_msg_body.slice_refs() == 0) ) { + op = OP::WITHDRAW; + ;; in few lines, amount to withdraw is loaded from in_msg_body, + ;; so we set it to the maximum avaliable balance + in_msg_body = begin_cell().store_coins(my_balance - msg_value - MIN_TON_FOR_STORAGE).end_cell().begin_parse(); + } else { + query_id = in_msg_body~load_uint(64); + } ;; owner role - cold wallet (private key that is not connected to the internet) that owns the funds used for staking and acts as the single nominator if (equal_slice_bits(sender, owner_address)) { From 4b0811d9b7a07e2d373980a8bc5120de7b72651c Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 30 Jan 2024 12:35:16 +0300 Subject: [PATCH 080/236] add missing packages for benchmark --- mytonctrl/scripts/upgrade.sh | 2 +- scripts/ton_installer.sh | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 57b98979..44cac111 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -29,7 +29,7 @@ COLOR='\033[92m' ENDC='\033[0m' # Установить дополнительные зависимости -apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio +apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio rocksdb-tools # bugfix if the files are in the wrong place wget "https://ton-blockchain.github.io/global.config.json" -O global.config.json diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index df42cd11..6cf9a990 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -50,11 +50,13 @@ if [ "$OSTYPE" == "linux-gnu" ]; then elif [ -f /etc/debian_version ]; then echo "Ubuntu/Debian Linux detected." apt-get update - apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev fio + apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev # Install ninja apt-get install -y ninja-build + # Install for benchmark + apt install -y fio rocksdb-tools else echo "Unknown Linux distribution." echo "This OS is not supported with this script at present. Sorry." From bf2de372958f31ce5ff5815013ed661090bf2a7f Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 1 Feb 2024 19:10:06 +0700 Subject: [PATCH 081/236] add duplicating externals to toncenter --- mytoncore/mytoncore.py | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 79f01b7f..e6a245f5 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -8,6 +8,7 @@ import psutil import subprocess import pkg_resources +import requests from fastcrc import crc16 from mytoncore.utils import xhex2hex, ng2g @@ -1200,14 +1201,35 @@ def SendFile(self, filePath, wallet=None, **kwargs): wallet.oldseqno = self.GetSeqno(wallet) self.liteClient.Run("sendfile " + filePath) if duplicateSendfile: - self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) - self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) + self.send_boc_toncenter(filePath) + # self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) + # self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) if timeout and wallet: self.WaitTransaction(wallet, timeout) if remove == True: os.remove(filePath) #end define + def send_boc_toncenter(self, file_path: str): + self.local.add_log('Start send_boc_toncenter function: ' + file_path, 'debug') + with open(file_path, "rb") as f: + boc = f.read() + boc_b64 = base64.b64encode(boc).decode("utf-8") + data = {"boc": boc_b64} + network_name = self.GetNetworkName() + if network_name == 'testnet': + url = 'https://testnet.toncenter.com/api/v2/sendBoc' + elif network_name == 'mainnet': + url = 'https://toncenter.com/api/v2/sendBoc' + else: + return False + result = requests.post(url=url, json=data) + if result.status_code != 200: + self.local.add_log(f'Failed to send boc to toncenter: {result.content}', 'info') + return False + self.local.add_log('Sent boc to toncenter', 'info') + return True + def WaitTransaction(self, wallet, timeout=30): self.local.add_log("start WaitTransaction function", "debug") timesleep = 3 From 1e5ca23e85643dc99e1071233cb1c93ed8c1ec2e Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 1 Feb 2024 19:39:12 +0700 Subject: [PATCH 082/236] fix zerostate hashes --- mytoncore/mytoncore.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index e6a245f5..5ee76387 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3585,11 +3585,11 @@ def activate_single_pool(self, pool): def GetNetworkName(self): data = self.local.read_db(self.liteClient.configPath) - mainnet_init_block_root_hash = "YRkrcmZMvLBvjanwKCyL3w4oceGPtFfgx8ym1QKCK/4=" - testnet_init_block_root_hash = "gj+B8wb/AmlPk1z1AhVI484rhrUpgSr2oSFIh56VoSg=" - if data.validator.init_block.root_hash == mainnet_init_block_root_hash: + mainnet_zero_state_root_hash = "F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=" + testnet_zero_state_root_hash = "gj+B8wb/AmlPk1z1AhVI484rhrUpgSr2oSFIh56VoSg=" + if data.validator.zero_state.root_hash == mainnet_zero_state_root_hash: return "mainnet" - elif data.validator.init_block.root_hash == testnet_init_block_root_hash: + elif data.validator.zero_state.root_hash == testnet_zero_state_root_hash: return "testnet" else: return "unknown" From be446b45ced8a6468ed1d54d5b00dea6b6f589f5 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 2 Feb 2024 07:58:34 +0300 Subject: [PATCH 083/236] add single-nominator-pool-r2 code hash --- mytoncore/mytoncore.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index d98a7ba3..e17410c6 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -533,6 +533,7 @@ def GetVersionFromCodeHash(self, inputHash): arr["hv1"] = "fc8e48ed7f9654ba76757f52cc6031b2214c02fab9e429ffa0340f5575f9f29c" arr["pool"] = "399838da9489139680e90fd237382e96ba771fdf6ea27eb7d513965b355038b4" arr["spool"] = "fc2ae44bcaedfa357d0091769aabbac824e1c28f14cc180c0b52a57d83d29054" + arr["spool_r2"] = "42bea8fea43bf803c652411976eb2981b9bdb10da84eb788a63ea7a01f2a044d" for version, hash in arr.items(): if hash == inputHash: return version From d602646d68af9ed07748cea2a98d2e79df02bc7e Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 5 Feb 2024 19:51:52 +0700 Subject: [PATCH 084/236] update slashing --- mytoncore/complaints/remove-proofs-v2.fif | 90 ++++++++++++++++++ mytoncore/functions.py | 12 +-- mytoncore/mytoncore.py | 110 +++++++++++++++++----- 3 files changed, 179 insertions(+), 33 deletions(-) create mode 100644 mytoncore/complaints/remove-proofs-v2.fif diff --git a/mytoncore/complaints/remove-proofs-v2.fif b/mytoncore/complaints/remove-proofs-v2.fif new file mode 100644 index 00000000..427615e5 --- /dev/null +++ b/mytoncore/complaints/remove-proofs-v2.fif @@ -0,0 +1,90 @@ +#!/usr/bin/fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." " cr + ."Removes proof cells from complaint." cr cr + + ." is a filename of the serialized TL-B ValidatorComplaint boc." cr + ."Saves the result boc into `.boc`." cr 1 halt +} : usage +$# 2 = { cr } { usage } cond + +$1 =: filename +$2 =: file-base + +filename file>B dup +8 B| drop B>$ "b5ee9c72" $= { B>$ x>B? drop } if +B>boc =: complaint + +."got: " cr +complaint ref, + ref, + b> // s, c +} : clear_producer_info + +{ // c + // c +} : clean_descr + +{ // c + // c +} : clean_descr_with_diff + + +// prod_info#34 utime:uint32 mc_blk_ref:ExtBlkRef state_proof:^(MERKLE_PROOF Block) +// prod_proof:^(MERKLE_PROOF ShardState) = ProducerInfo; +// +// no_blk_gen#450e8bd9 from_utime:uint32 prod_info:^ProducerInfo = ComplaintDescr; +// no_blk_gen_diff#c737b0ca prod_info_old:^ProducerInfo prod_info_new:^ProducerInfo = ComplaintDescr; +// +// validator_complaint#bc validator_pubkey:bits256 description:^ComplaintDescr created_at:uint32 severity:uint8 reward_addr:uint256 paid:Grams suggested_fine:Grams suggested_fine_part:uint32 = ValidatorComplaint; + +complaint =: result_cell + +"result: " type cr +result_cell B +file-base +".boc" B>file + diff --git a/mytoncore/functions.py b/mytoncore/functions.py index efa14c4d..c28c4b64 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -504,13 +504,11 @@ def Complaints(local, ton): # 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) + complaints = ton.GetComplaints(electionId) # get complaints from Elector + for c in complaints.values(): + complaint_hash = c.get("hash") + if ton.complaint_is_valid(c): + ton.VoteComplaint(electionId, complaint_hash) # end define diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 5ee76387..e8da64d4 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -560,7 +560,7 @@ def GetFullConfigAddr(self): result = self.liteClient.Run("getconfig 0") configAddr_hex = self.GetVarFromWorkerOutput(result, "config_addr:x") fullConfigAddr = "-1:{configAddr_hex}".format(configAddr_hex=configAddr_hex) - + # Set buffer self.SetFunctionBuffer(bname, fullConfigAddr) return fullConfigAddr @@ -615,7 +615,7 @@ def GetFullDnsRootAddr(self): result = self.liteClient.Run("getconfig 4") dnsRootAddr_hex = self.GetVarFromWorkerOutput(result, "dns_root_addr:x") fullDnsRootAddr = "-1:{dnsRootAddr_hex}".format(dnsRootAddr_hex=dnsRootAddr_hex) - + # Set buffer self.SetFunctionBuffer(bname, fullDnsRootAddr) return fullDnsRootAddr @@ -636,7 +636,7 @@ def GetActiveElectionId(self, fullElectorAddr): activeElectionId = activeElectionId.replace(' ', '') activeElectionId = parse(activeElectionId, '[', ']') activeElectionId = int(activeElectionId) - + # Set buffer self.SetFunctionBuffer(bname, activeElectionId) return activeElectionId @@ -865,7 +865,7 @@ def GetConfig(self, configId): start = result.find("ConfigParam") text = result[start:] data = self.Tlb2Json(text) - + # Set buffer self.SetFunctionBuffer(bname, data) return data @@ -920,7 +920,7 @@ def GetConfig32(self): buff["weight"] = validatorWeight validators.append(buff) config32["validators"] = validators - + # Set buffer self.SetFunctionBuffer(bname, config32) return config32 @@ -957,7 +957,7 @@ def GetConfig34(self): buff["weight"] = validatorWeight validators.append(buff) config34["validators"] = validators - + # Set buffer self.SetFunctionBuffer(bname, config34) return config34 @@ -994,7 +994,7 @@ def GetConfig36(self): except: config36["validators"] = list() #end try - + # Set buffer self.SetFunctionBuffer(bname, config36) return config36 @@ -1085,7 +1085,7 @@ def CreateConfigProposalRequest(self, offerHash, validatorIndex): return var1 #end define - def CreateComplaintRequest(self, electionId , complaintHash, validatorIndex): + def CreateComplaintRequest(self, electionId, complaintHash, validatorIndex): 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] @@ -1103,6 +1103,15 @@ def CreateComplaintRequest(self, electionId , complaintHash, validatorIndex): return var1 #end define + def remove_proofs_from_complaint(self, input_file_name: str): + self.local.add_log("start remove_proofs_from_complaint function", "debug") + output_file_name = self.tempDir + "complaint-new.boc" + fift_script = pkg_resources.resource_filename('mytoncore', 'complaints/remove-proofs-v2.fif') + args = [fift_script, input_file_name, output_file_name] + result = self.fift.Run(args) + return output_file_name + + def PrepareComplaint(self, electionId, inputFileName): self.local.add_log("start PrepareComplaint function", "debug") fileName = self.tempDir + "complaint-msg-body.boc" @@ -1160,7 +1169,7 @@ def SignBocWithWallet(self, wallet, boc_path, dest, coins, **kwargs): if account.balance < coins + 0.1: raise Exception("Wallet balance is less than requested coins") #end if - + # Bounceable checking destAccount = self.GetAccount(dest) bounceable = self.IsBounceableAddrB64(dest) @@ -1760,7 +1769,7 @@ def GetValidatorConfig(self): vconfig = json.loads(text) return Dict(vconfig) #end define - + def GetOverlaysStats(self): self.local.add_log("start GetOverlaysStats function", "debug") resultFilePath = self.local.buffer.my_temp_dir + "getoverlaysstats.json" @@ -1811,7 +1820,7 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): if account.status != "active": raise Exception("Wallet account is uninitialized") #end if - + # Bounceable checking destAccount = self.GetAccount(dest) bounceable = self.IsBounceableAddrB64(dest) @@ -2334,10 +2343,12 @@ def SaveComplaints(self, electionId): return complaintsHashes #end define - def CheckComplaint(self, filePath): + def CheckComplaint(self, file_path: str): self.local.add_log("start CheckComplaint function", "debug") - cmd = "loadproofcheck {filePath}".format(filePath=filePath) + cmd = "loadproofcheck {filePath}".format(filePath=file_path) result = self.liteClient.Run(cmd, timeout=30) + if 'error' in result.lower(): + return self.check_invalid_complaint(file_path) lines = result.split('\n') ok = False for line in lines: @@ -2350,6 +2361,52 @@ def CheckComplaint(self, filePath): return ok #end define + def complaint_is_valid(self, complaint: dict): + self.local.add_log("start complaint_is_valid function", "debug") + + voted_complaints = self.GetVotedComplaints() + if complaint['pseudohash'] in voted_complaints: + self.local.add_log(f"skip checking complaint {complaint['hash']}: " + f"complaint with this pseudohash ({complaint['pseudohash']})" + f" has already been voted", "debug") + return False + + # check that complaint is valid + election_id = complaint['electionId'] + config32 = self.GetConfig32() + start = config32.get("startWorkTime") + if election_id != start: + self.local.add_log(f"skip checking complaint {complaint['hash']}: " + f"election_id ({election_id}) doesn't match with " + f"start work time ({config32.get('startWorkTime')})", "info") + return False + end = config32.get("endWorkTime") + data = self.GetValidatorsLoad(start, end - 60, saveCompFiles=False) + + exists = False + for item in data.values(): + pubkey = item.get("pubkey") + if pubkey is None: + continue + pseudohash = pubkey + str(election_id) + if pseudohash == complaint['pseudohash']: + exists = True + break + + if not exists: + self.local.add_log(f"complaint {complaint['hash']} declined: complaint info was not found", "info") + return False + + # check complaint fine value + if complaint['suggestedFine'] != 101: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3708 + self.local.add_log(f"complaint {complaint['hash']} declined: complaint fine value is {complaint['suggestedFine']} ton", "info") + return False + if complaint['suggestedFinePart'] != 0: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3709 + self.local.add_log(f"complaint {complaint['hash']} declined: complaint fine part value is {complaint['suggestedFinePart']} ton", "info") + return False + + return True + def GetOnlineValidators(self): onlineValidators = list() validators = self.GetValidatorsList() @@ -2452,7 +2509,7 @@ def GetValidatorsList(self, past=False): if buff: return buff #end if - + timestamp = get_timestamp() end = timestamp - 60 start = end - 2000 @@ -2477,7 +2534,7 @@ def GetValidatorsList(self, past=False): if saveElectionEntries and adnlAddr in saveElectionEntries: validator["walletAddr"] = saveElectionEntries[adnlAddr]["walletAddr"] #end for - + # Set buffer self.SetFunctionBuffer(bname, validators) return validators @@ -2508,6 +2565,7 @@ def CheckValidators(self, start, end): if pseudohash in complaints: continue # Create complaint + fileName = self.remove_proofs_from_complaint(fileName) fileName = self.PrepareComplaint(electionId, fileName) fileName = self.SignBocWithWallet(wallet, fileName, fullElectorAddr, 300) self.SendFile(fileName, wallet) @@ -2949,7 +3007,7 @@ def ParseAddrB64(self, addrB64): if buff: return buff #end if - + buff = addrB64.replace('-', '+') buff = buff.replace('_', '/') buff = buff.encode() @@ -2983,7 +3041,7 @@ def ParseAddrB64(self, addrB64): workchain = int.from_bytes(workchain_bytes, "big", signed=True) addr = addr_bytes.hex() - + # Set buffer data = (workchain, addr, bounceable) self.SetFunctionBuffer(fname, data) @@ -3010,7 +3068,7 @@ def ParseInputAddr(self, inputAddr): else: raise Exception(f"ParseInputAddr error: input address is not a adress: {inputAddr}") #end define - + def IsBounceableAddrB64(self, inputAddr): bounceable = None try: @@ -3326,7 +3384,7 @@ def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, if "Saved pool" not in result: raise Exception("CreatePool error: " + result) #end if - + pools = self.GetPools() newPool = self.GetLocalPool(poolName) for pool in pools: @@ -3357,7 +3415,7 @@ def DepositToPool(self, poolAddr, amount): resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, amount) self.SendFile(resultFilePath, wallet) #end define - + def WithdrawFromPool(self, poolAddr, amount): poolData = self.GetPoolData(poolAddr) if poolData["state"] == 0: @@ -3376,20 +3434,20 @@ def WithdrawFromPoolProcess(self, poolAddr, amount): resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, 1.35) self.SendFile(resultFilePath, wallet) #end define - + def PendWithdrawFromPool(self, poolAddr, amount): self.local.add_log("start PendWithdrawFromPool function", "debug") pendingWithdraws = self.GetPendingWithdraws() pendingWithdraws[poolAddr] = amount self.local.save() #end define - + def HandlePendingWithdraw(self, pendingWithdraws, poolAddr): amount = pendingWithdraws.get(poolAddr) self.WithdrawFromPoolProcess(poolAddr, amount) pendingWithdraws.pop(poolAddr) #end define - + def GetPendingWithdraws(self): bname = "pendingWithdraws" pendingWithdraws = self.local.db.get(bname) @@ -3565,7 +3623,7 @@ def create_single_pool(self, pool_name, owner_address): if "Saved single nominator pool" not in result: raise Exception("create_single_pool error: " + result) #end if - + pools = self.GetPools() new_pool = self.GetLocalPool(pool_name) for pool in pools: @@ -3594,7 +3652,7 @@ def GetNetworkName(self): else: return "unknown" #end define - + def GetFunctionBuffer(self, name, timeout=10): timestamp = get_timestamp() buff = self.local.buffer.get(name) @@ -3607,7 +3665,7 @@ def GetFunctionBuffer(self, name, timeout=10): data = buff.get("data") return data #end define - + def SetFunctionBuffer(self, name, data): buff = dict() buff["time"] = get_timestamp() From 7add95d4953f7c9f57e6b7613bac0557920f0060 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 6 Feb 2024 12:25:05 +0700 Subject: [PATCH 085/236] bugfix --- mytoncore/mytoncore.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index e8da64d4..d5b043a7 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2347,8 +2347,6 @@ def CheckComplaint(self, file_path: str): self.local.add_log("start CheckComplaint function", "debug") cmd = "loadproofcheck {filePath}".format(filePath=file_path) result = self.liteClient.Run(cmd, timeout=30) - if 'error' in result.lower(): - return self.check_invalid_complaint(file_path) lines = result.split('\n') ok = False for line in lines: From 10854ced2fa3baff8cc78115ee77fc356f080a8a Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:12:06 +0300 Subject: [PATCH 086/236] add remove-proofs-v2.fif to package files --- setup.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 21363e7d..26b16bd4 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,10 @@ ], package_data={ 'mytoninstaller.scripts': ['*.sh'], - 'mytoncore.contracts' :['single-nominator-pool/*'], + 'mytoncore': [ + 'contracts/*', + 'complaints/*' + ], 'mytonctrl': [ 'resources/*', 'scripts/*', From 1dcc169bc89354df71b2eaeaa4e19b79421e900a Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 6 Feb 2024 12:38:44 +0300 Subject: [PATCH 087/236] bugfix `.boc` duplicate --- mytoncore/complaints/remove-proofs-v2.fif | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mytoncore/complaints/remove-proofs-v2.fif b/mytoncore/complaints/remove-proofs-v2.fif index 427615e5..0079dfab 100644 --- a/mytoncore/complaints/remove-proofs-v2.fif +++ b/mytoncore/complaints/remove-proofs-v2.fif @@ -1,16 +1,16 @@ #!/usr/bin/fift -s "TonUtil.fif" include -{ ."usage: " @' $0 type ." " cr +{ ."usage: " @' $0 type ." " cr ."Removes proof cells from complaint." cr cr ." is a filename of the serialized TL-B ValidatorComplaint boc." cr - ."Saves the result boc into `.boc`." cr 1 halt + ."Saves the result boc into ``." cr 1 halt } : usage $# 2 = { cr } { usage } cond $1 =: filename -$2 =: file-base +$2 =: savefile filename file>B dup 8 B| drop B>$ "b5ee9c72" $= { B>$ x>B? drop } if @@ -86,5 +86,5 @@ b> =: result_cell result_cell B -file-base +".boc" B>file - +savefile tuck B>file +."(Saved to file " type .")" cr From 1875f51cd5447890da79d3b6288d01b7c3147866 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 6 Feb 2024 13:09:29 +0300 Subject: [PATCH 088/236] add `duplicateApi` and `duplicateApiUrl` --- mytoncore/mytoncore.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 639a99f5..1c4b3a06 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1205,15 +1205,19 @@ def SendFile(self, filePath, wallet=None, **kwargs): timeout = kwargs.get("timeout", 30) remove = kwargs.get("remove", True) duplicateSendfile = self.local.db.get("duplicateSendfile", True) + duplicateApi = self.local.db.get("duplicateApi", False) if not os.path.isfile(filePath): raise Exception("SendFile error: no such file '{filePath}'".format(filePath=filePath)) if timeout and wallet: wallet.oldseqno = self.GetSeqno(wallet) self.liteClient.Run("sendfile " + filePath) if duplicateSendfile: + try: + self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) + self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) + except: pass + if duplicateApi: self.send_boc_toncenter(filePath) - # self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) - # self.liteClient.Run("sendfile " + filePath, useLocalLiteServer=False) if timeout and wallet: self.WaitTransaction(wallet, timeout) if remove == True: @@ -1228,10 +1232,13 @@ def send_boc_toncenter(self, file_path: str): data = {"boc": boc_b64} network_name = self.GetNetworkName() if network_name == 'testnet': - url = 'https://testnet.toncenter.com/api/v2/sendBoc' + default_url = 'https://testnet.toncenter.com/api/v2/sendBoc' elif network_name == 'mainnet': - url = 'https://toncenter.com/api/v2/sendBoc' + default_url = 'https://toncenter.com/api/v2/sendBoc' else: + default_url = None + url = self.local.db.get("duplicateApiUrl", default_url) + if url == None: return False result = requests.post(url=url, json=data) if result.status_code != 200: From 8bcc5be3577498d115b53bdd5e64989ba70962d8 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:02:46 +0300 Subject: [PATCH 089/236] bugfix event --- mytoninstaller/mytoninstaller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 67306b9c..3400df55 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -181,6 +181,7 @@ def Event(local, name): initBlock_b64 = sys.argv[ix+1] initBlock = b642dict(initBlock_b64) CreateLocalConfig(local, initBlock) + local.exit() #end define From be93606992f7d0f8bd365ccf363702fecffb96ef Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 6 Feb 2024 21:02:14 +0700 Subject: [PATCH 090/236] fix get config 32 and 34 for 1 validator --- mytoncore/mytoncore.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index d5b043a7..20dbd5f7 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -910,9 +910,9 @@ def GetConfig32(self): if "public_key:" in line: validatorAdnlAddr = parse(line, "adnl_addr:x", ')') pubkey = parse(line, "pubkey:x", ')') - if config32["totalValidators"] > 1: + try: validatorWeight = int(parse(line, "weight:", ' ')) - else: + except ValueError: validatorWeight = int(parse(line, "weight:", ')')) buff = dict() buff["adnlAddr"] = validatorAdnlAddr @@ -947,9 +947,9 @@ def GetConfig34(self): if "public_key:" in line: validatorAdnlAddr = parse(line, "adnl_addr:x", ')') pubkey = parse(line, "pubkey:x", ')') - if config34["totalValidators"] > 1: + try: validatorWeight = int(parse(line, "weight:", ' ')) - else: + except ValueError: validatorWeight = int(parse(line, "weight:", ')')) buff = dict() buff["adnlAddr"] = validatorAdnlAddr From 04b08d66e50c2c4e6507a61d71648f3379c16322 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Tue, 6 Feb 2024 20:16:28 +0300 Subject: [PATCH 091/236] bugfix data print --- mytonctrl/mytonctrl.py | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 168a0ebc..cd161f58 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -901,8 +901,8 @@ def PrintBookmarksList(ton, args): name = item.get("name") type = item.get("type") addr = item.get("addr") - data = item.get("data") - table += [[name, type, addr, data]] + bookmark_data = item.get("data") + table += [[name, type, addr, bookmark_data]] print_table(table) #end define @@ -948,14 +948,17 @@ def DeleteBookmark(ton, args): # #end define def PrintOffersList(ton, args): - offers = ton.GetOffers() + data = ton.GetOffers() + if (data is None or len(data) == 0): + print("No data") + return if "--json" in args: - text = json.dumps(offers, indent=2) + text = json.dumps(data, indent=2) print(text) else: table = list() table += [["Hash", "Votes", "W/L", "Approved", "Is passed"]] - for item in offers: + for item in data: hash = item.get("hash") votedValidators = len(item.get("votedValidators")) wins = item.get("wins") @@ -1007,14 +1010,17 @@ def GetConfig(ton, args): def PrintComplaintsList(ton, args): past = "past" in args - complaints = ton.GetComplaints(past=past) + data = ton.GetComplaints(past=past) + if (data is None or len(complaints)data 0): + print("No data") + return if "--json" in args: - text = json.dumps(complaints, indent=2) + text = json.dumps(data, indent=2) print(text) else: table = list() table += [["Election id", "ADNL", "Fine (part)", "Votes", "Approved", "Is passed"]] - for key, item in complaints.items(): + for key, item in data.items(): electionId = item.get("electionId") adnl = item.get("adnl") suggestedFine = item.get("suggestedFine") @@ -1117,14 +1123,17 @@ def GetDomainFromAuction(ton, args): def PrintElectionEntriesList(ton, args): past = "past" in args - entries = ton.GetElectionEntries(past=past) + data = ton.GetElectionEntries(past=past) + if (data is None or len(data) == 0): + print("No data") + return if "--json" in args: - text = json.dumps(entries, indent=2) + text = json.dumps(data, indent=2) print(text) else: table = list() table += [["ADNL", "Pubkey", "Wallet", "Stake", "Max-factor"]] - for key, item in entries.items(): + for key, item in data.items(): adnl = item.get("adnlAddr") pubkey = item.get("pubkey") walletAddr = item.get("walletAddr") @@ -1147,14 +1156,17 @@ def VoteElectionEntry(ton, args): def PrintValidatorList(ton, args): past = "past" in args - validators = ton.GetValidatorsList(past=past) + data = ton.GetValidatorsList(past=past) + if (data is None or len(data) == 0): + print("No data") + return if "--json" in args: - text = json.dumps(validators, indent=2) + text = json.dumps(data, indent=2) print(text) else: table = list() table += [["ADNL", "Pubkey", "Wallet", "Efficiency", "Online"]] - for item in validators: + for item in data: adnl = item.get("adnlAddr") pubkey = item.get("pubkey") walletAddr = item.get("walletAddr") From b49a3bf949bda5749680928143ba124968890b57 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 7 Feb 2024 14:30:15 +0700 Subject: [PATCH 092/236] change slashing cron time for testnets --- mytoncore/functions.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index c28c4b64..2cc4ec50 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -558,15 +558,20 @@ def ScanLiteServers(local, ton): def General(local): local.add_log("start General function", "debug") ton = MyTonCore(local) - scanner = Dict() + # scanner = Dict() # scanner.Run() - # Запустить потоки + # Start threads 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, )) + + t = 600 + if ton.GetNetworkName() != 'mainnet': + t = 60 + local.start_cycle(Complaints, sec=t, args=(local, ton, )) + local.start_cycle(Slashing, sec=t, 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, )) From f502a7b90a3317b00a10608fa79794d60951a1d7 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 7 Feb 2024 11:21:37 +0300 Subject: [PATCH 093/236] bugfix --- mytonctrl/mytonctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index cd161f58..06a4d8ac 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1011,7 +1011,7 @@ def GetConfig(ton, args): def PrintComplaintsList(ton, args): past = "past" in args data = ton.GetComplaints(past=past) - if (data is None or len(complaints)data 0): + if (data is None or len(data) == 0): print("No data") return if "--json" in args: From 2a2a4e7811172efb24606d6615b197c5f1b44e08 Mon Sep 17 00:00:00 2001 From: yungwine Date: Sat, 10 Feb 2024 14:53:34 +0700 Subject: [PATCH 094/236] add checking for freezetime before complaints --- mytoncore/functions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 2cc4ec50..2b654dc0 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -523,6 +523,10 @@ def Slashing(local, ton): config32 = ton.GetConfig32() start = config32.get("startWorkTime") end = config32.get("endWorkTime") + config15 = ton.GetConfig15() + ts = get_timestamp() + if not(end < ts < end + config15['stakeHeldFor']): # check that currently is freeze time + return local.add_log("slash_time {}, start {}, end {}".format(slash_time, start, end), "debug") if slash_time != start: end -= 60 From 5c2f1f1e9d1caa0daab43c7118ddb3292c728d6a Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 14 Feb 2024 14:34:45 +0700 Subject: [PATCH 095/236] fix GetSaveOffers() --- mytoncore/mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 3d18fb6b..1ee3038e 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2941,7 +2941,7 @@ def WriteBookmarkData(self, bookmark): def GetSaveOffers(self): bname = "saveOffers" saveOffers = self.local.db.get(bname) - if type(saveOffers) != dict: + if saveOffers is None: saveOffers = dict() self.local.db[bname] = saveOffers return saveOffers From 74fdbe66c71b6f2c659da154440833e557b9de31 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 14 Feb 2024 17:55:30 +0700 Subject: [PATCH 096/236] fix GetSaveComplaints() --- mytoncore/mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 1ee3038e..63c47e89 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2229,7 +2229,7 @@ def GetComplaints(self, electionId=None, past=False): def GetSaveComplaints(self): timestamp = get_timestamp() saveComplaints = self.local.db.get("saveComplaints") - if type(saveComplaints) is not dict: + if saveComplaints is None: saveComplaints = dict() self.local.db["saveComplaints"] = saveComplaints buff = saveComplaints.copy() From 0a130ee424bfedd261ce5900f91b337b4e816db6 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 15 Feb 2024 16:50:15 +0700 Subject: [PATCH 097/236] fix GetValidatorKey() --- mytoncore/mytoncore.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 63c47e89..43b9b420 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1911,12 +1911,13 @@ def MoveCoinsFromHW(self, wallet, destList, **kwargs): def GetValidatorKey(self): vconfig = self.GetValidatorConfig() - for validator in vconfig["validators"]: + validators = sorted(vconfig["validators"], key=lambda i: i['election_date'], reverse=True) + for validator in validators: validatorId = validator["id"] key_bytes = base64.b64decode(validatorId) validatorKey = key_bytes.hex().upper() timestamp = get_timestamp() - if timestamp > validator["election_date"]: + if validator["election_date"] < timestamp < validator["expire_at"]: return validatorKey raise Exception("GetValidatorKey error: validator key not found. Are you sure you are a validator?") #end define From c28197dbd2953794f82ef3f813fa1cb9bfe264ff Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 15 Feb 2024 17:18:27 +0700 Subject: [PATCH 098/236] change duplicateApi default behaviour --- mytoncore/mytoncore.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 43b9b420..f49a4eba 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1205,7 +1205,8 @@ def SendFile(self, filePath, wallet=None, **kwargs): timeout = kwargs.get("timeout", 30) remove = kwargs.get("remove", True) duplicateSendfile = self.local.db.get("duplicateSendfile", True) - duplicateApi = self.local.db.get("duplicateApi", False) + telemetry = self.local.db.get("sendTelemetry", False) + duplicateApi = self.local.db.get("duplicateApi", telemetry) if not os.path.isfile(filePath): raise Exception("SendFile error: no such file '{filePath}'".format(filePath=filePath)) if timeout and wallet: From f54ded076af11c5d584a3ddecbb8cdf4ff028510 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 16 Feb 2024 14:07:27 +0700 Subject: [PATCH 099/236] refactor complaints --- mytoncore/mytoncore.py | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index f49a4eba..eaa1268c 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2185,6 +2185,7 @@ def GetComplaints(self, electionId=None, past=False): buff = subdata[0] # *complaint* item["electionId"] = electionId item["hash"] = chash + item["hash_hex"] = dec2hex(chash) pubkey = Dec2HexAddr(buff[0]) # *validator_pubkey* adnl = self.GetAdnlFromPubkey(pubkey) item["pubkey"] = pubkey @@ -2324,18 +2325,11 @@ def VoteComplaint(self, electionId, complaintHash): validatorKey = self.GetValidatorKey() validatorPubkey_b64 = self.GetPubKeyBase64(validatorKey) validatorIndex = self.GetValidatorIndex() - complaint = self.GetComplaint(electionId, complaintHash) - votedValidators = complaint.get("votedValidators") - pubkey = complaint.get("pubkey") - if validatorIndex in votedValidators: - self.local.add_log("Complaint already has been voted", "info") - return var1 = self.CreateComplaintRequest(electionId, complaintHash, validatorIndex) validatorSignature = self.GetValidatorSignature(validatorKey, var1) resultFilePath = self.SignComplaintVoteRequestWithValidator(complaintHash, electionId, validatorIndex, validatorPubkey_b64, validatorSignature) resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, fullElectorAddr, 1.5) self.SendFile(resultFilePath, wallet) - self.AddVotedComplaints(complaint) #end define def SaveComplaints(self, electionId): @@ -2377,19 +2371,19 @@ def CheckComplaint(self, file_path: str): def complaint_is_valid(self, complaint: dict): self.local.add_log("start complaint_is_valid function", "debug") - voted_complaints = self.GetVotedComplaints() + election_id = complaint['electionId'] + voted_complaints = self.GetVotedComplaints(election_id) if complaint['pseudohash'] in voted_complaints: - self.local.add_log(f"skip checking complaint {complaint['hash']}: " + self.local.add_log(f"skip checking complaint {complaint['hash_hex']}: " f"complaint with this pseudohash ({complaint['pseudohash']})" f" has already been voted", "debug") return False # check that complaint is valid - election_id = complaint['electionId'] config32 = self.GetConfig32() start = config32.get("startWorkTime") if election_id != start: - self.local.add_log(f"skip checking complaint {complaint['hash']}: " + self.local.add_log(f"skip checking complaint {complaint['hash_hex']}: " f"election_id ({election_id}) doesn't match with " f"start work time ({config32.get('startWorkTime')})", "info") return False @@ -2407,15 +2401,15 @@ def complaint_is_valid(self, complaint: dict): break if not exists: - self.local.add_log(f"complaint {complaint['hash']} declined: complaint info was not found", "info") + self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint info was not found", "info") return False # check complaint fine value if complaint['suggestedFine'] != 101: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3708 - self.local.add_log(f"complaint {complaint['hash']} declined: complaint fine value is {complaint['suggestedFine']} ton", "info") + self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine value is {complaint['suggestedFine']} ton", "info") return False if complaint['suggestedFinePart'] != 0: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3709 - self.local.add_log(f"complaint {complaint['hash']} declined: complaint fine part value is {complaint['suggestedFinePart']} ton", "info") + self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine part value is {complaint['suggestedFinePart']} ton", "info") return False return True @@ -2958,13 +2952,17 @@ def AddSaveOffer(self, offer): self.local.save() #end define - def GetVotedComplaints(self): - bname = "votedComplaints" - votedComplaints = self.local.db.get(bname) - if votedComplaints is None: - votedComplaints = dict() - self.local.db[bname] = votedComplaints - return votedComplaints + def GetVotedComplaints(self, election_id: int = None): + complaints = self.GetComplaints(election_id) + result = {} + validator_index = self.GetValidatorIndex() + for complaint in complaints.values(): + votedValidators = complaint.get("votedValidators") + if validator_index in votedValidators: + pubkey = complaint.get("pubkey") + election_id = complaint.get("electionId") + result[pubkey + str(election_id)] = complaint + return result #end define def AddVotedComplaints(self, complaint): From f9353b7121b10c80209271b0c31e9ae4266bc873 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 16 Feb 2024 14:10:46 +0700 Subject: [PATCH 100/236] improves --- mytoncore/mytoncore.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index eaa1268c..b515d01b 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2956,12 +2956,10 @@ def GetVotedComplaints(self, election_id: int = None): complaints = self.GetComplaints(election_id) result = {} validator_index = self.GetValidatorIndex() - for complaint in complaints.values(): + for pseudohash, complaint in complaints.items(): votedValidators = complaint.get("votedValidators") if validator_index in votedValidators: - pubkey = complaint.get("pubkey") - election_id = complaint.get("electionId") - result[pubkey + str(election_id)] = complaint + result[pseudohash] = complaint return result #end define From 3fae1ff4012d72de0c710abf1102afdac4b01213 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 20 Feb 2024 14:24:19 +0700 Subject: [PATCH 101/236] fix autovoting --- mytoncore/functions.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 2b654dc0..4ca0c3f0 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -347,12 +347,15 @@ def GetBlockTimeAvg(local, timediff): def Offers(local, ton): - saveOffers = ton.GetSaveOffers() + save_offers = ton.GetSaveOffers() offers = ton.GetOffers() for offer in offers: - offerHash = offer.get("hash") - if offerHash in saveOffers: - ton.VoteOffer(offerHash) + offer_hash = offer.get("hash") + if offer_hash in save_offers: + offer_pseudohash = offer.get("pseudohash") + save_offer_pseudohash = save_offers.get(offer_hash) + if offer_pseudohash == save_offer_pseudohash and offer_pseudohash is not None: + ton.VoteOffer(offer_hash) # end define From ecf0fe9bdd288ca956384e24d65d5412131ae066 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 22 Feb 2024 14:31:17 +0700 Subject: [PATCH 102/236] update signle nominator usage --- mytoncore/mytoncore.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index b515d01b..81fe2c8c 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1307,7 +1307,10 @@ def GetStake(self, account, args=None): stake = account.balance - 10 #end if - if stake is None and usePool: + pool_version = self.GetVersionFromCodeHash(account.codeHash) + is_single_nominator = 'spool' in pool_version + + if stake is None and usePool and not is_single_nominator: stake = account.balance - 20 if stake is None: sp = stakePercent / 100 From 679879b9c113e7a4e2cad26211286d8130c54f8f Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 22 Feb 2024 20:50:27 +0700 Subject: [PATCH 103/236] add recursive package_data for contracts --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 26b16bd4..1d991cca 100644 --- a/setup.py +++ b/setup.py @@ -24,7 +24,7 @@ package_data={ 'mytoninstaller.scripts': ['*.sh'], 'mytoncore': [ - 'contracts/*', + 'contracts/**/*', 'complaints/*' ], 'mytonctrl': [ From 45b96a7a9cb1c962c0140a33bbfeac273eee51b5 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 23 Feb 2024 13:55:22 +0700 Subject: [PATCH 104/236] fix git config --- mytonctrl/mytonctrl.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 06a4d8ac..b4a7768a 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -225,9 +225,26 @@ def check_vport(local, ton): color_print(local.translate("vport_error")) #end define + +def fix_git_config(git_path: str): + args = ["git", "status"] + try: + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=git_path, timeout=3) + err = process.stderr.decode("utf-8") + except Exception as e: + err = str(e) + if err: + if 'git config --global --add safe.directory' in err: + args = ["git", "config", "--global", "--add", "safe.directory", git_path] + subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + else: + raise Exception(f'Failed to check git status: {err}') + + def check_git(input_args, default_repo, text): src_dir = "/usr/src" git_path = f"{src_dir}/{default_repo}" + fix_git_config(git_path) default_author = "ton-blockchain" default_branch = "master" From 32afd4d34461280f6b5c30f4e894c3377b4268c2 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 23 Feb 2024 22:20:33 +0700 Subject: [PATCH 105/236] dont participate in elections if there is no adnl address in vconfig --- mytoncore/mytoncore.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 81fe2c8c..152fcdbf 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1436,6 +1436,18 @@ def ElectionEntry(self, args=None): if (startWorkTime - now) > self.local.db["participateBeforeEnd"] and \ (now + self.local.db["periods"]["elections"]) < startWorkTime: return + + vconfig = self.GetValidatorConfig() + + have_adnl = False + # Check if ADNL address is in the list + for a in vconfig.adnl: + if base64.b64decode(a.id).hex() == adnlAddr: + have_adnl = True + break + if not have_adnl: + raise Exception('ADNL address is not found') + # Check if election entry already completed entries = self.GetElectionEntries() if adnlAddr in entries: From 777b1bf1d7da3f2860c96542e6a48eb4e0fa95de Mon Sep 17 00:00:00 2001 From: yungwine Date: Sat, 24 Feb 2024 00:29:18 +0700 Subject: [PATCH 106/236] bugfix --- mytoncore/mytoncore.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 152fcdbf..a92eb1bd 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1428,7 +1428,8 @@ def ElectionEntry(self, args=None): #end if # Get ADNL address - adnlAddr = self.GetAdnlAddr() + adnl_addr = self.GetAdnlAddr() + adnl_addr_bytes = bytes.fromhex(adnl_addr) # Check wether it is too early to participate if "participateBeforeEnd" in self.local.db: @@ -1442,7 +1443,7 @@ def ElectionEntry(self, args=None): have_adnl = False # Check if ADNL address is in the list for a in vconfig.adnl: - if base64.b64decode(a.id).hex() == adnlAddr: + if base64.b64decode(a.id) == adnl_addr_bytes: have_adnl = True break if not have_adnl: @@ -1450,7 +1451,7 @@ def ElectionEntry(self, args=None): # Check if election entry already completed entries = self.GetElectionEntries() - if adnlAddr in entries: + if adnl_addr in entries: self.local.add_log("Elections entry already completed", "info") return #end if @@ -1468,24 +1469,24 @@ def ElectionEntry(self, args=None): validatorPubkey_b64 = self.GetPubKeyBase64(validatorKey) # Attach ADNL addr to validator - self.AttachAdnlAddrToValidator(adnlAddr, validatorKey, endWorkTime) + self.AttachAdnlAddrToValidator(adnl_addr, validatorKey, endWorkTime) # Get max factor maxFactor = self.GetMaxFactor() # Create fift's. Continue with pool or walet if usePool: - var1 = self.CreateElectionRequest(pool, startWorkTime, adnlAddr, maxFactor) + var1 = self.CreateElectionRequest(pool, startWorkTime, adnl_addr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) - validatorPubkey, resultFilePath = self.SignElectionRequestWithPoolWithValidator(pool, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) + validatorPubkey, resultFilePath = self.SignElectionRequestWithPoolWithValidator(pool, startWorkTime, adnl_addr, validatorPubkey_b64, validatorSignature, maxFactor, stake) # Send boc file to TON resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 1.3) self.SendFile(resultFilePath, wallet) else: - var1 = self.CreateElectionRequest(wallet, startWorkTime, adnlAddr, maxFactor) + var1 = self.CreateElectionRequest(wallet, startWorkTime, adnl_addr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) - validatorPubkey, resultFilePath = self.SignElectionRequestWithValidator(wallet, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor) + validatorPubkey, resultFilePath = self.SignElectionRequestWithValidator(wallet, startWorkTime, adnl_addr, validatorPubkey_b64, validatorSignature, maxFactor) # Send boc file to TON resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, fullElectorAddr, stake) @@ -1493,7 +1494,7 @@ def ElectionEntry(self, args=None): #end if # 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) + 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=adnl_addr, var1=var1, validatorSignature=validatorSignature, validatorPubkey=validatorPubkey) self.local.add_log("ElectionEntry completed. Start work time: " + str(startWorkTime)) #end define From bd6f79a7ac93726a0ec916f8dd8c4d1ab923b733 Mon Sep 17 00:00:00 2001 From: neodiX Date: Sun, 25 Feb 2024 09:54:08 +0100 Subject: [PATCH 107/236] Clone OpenSSL using tag name instead of branch name --- mytonctrl/scripts/upgrade.sh | 3 ++- scripts/ton_installer.sh | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 44cac111..408b1cbb 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -50,11 +50,12 @@ fi # compile openssl_3 rm -rf ${bindir}/openssl_3 -git clone --branch openssl-3.1.4 https://github.com/openssl/openssl ${bindir}/openssl_3 +git clone https://github.com/openssl/openssl ${bindir}/openssl_3 cd ${bindir}/openssl_3 ./config make build_libs -j$(nproc) opensslPath=`pwd` +git checkout openssl-3.1.4 # Go to work dir cd ${srcdir} diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 6cf9a990..9f053379 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -92,10 +92,10 @@ pip3 install psutil crc16 requests # build openssl 3.0 echo -e "${COLOR}[2/6]${ENDC} Building OpenSSL 3.0" rm -rf $BIN_DIR/openssl_3 -git clone --branch openssl-3.1.4 https://github.com/openssl/openssl $BIN_DIR/openssl_3 +git clone https://github.com/openssl/openssl $BIN_DIR/openssl_3 cd $BIN_DIR/openssl_3 opensslPath=`pwd` -git checkout +git checkout openssl-3.1.4 ./config make build_libs -j$(nproc) From cb83ecf6465e75fd872f0fea889a4052307cc4a9 Mon Sep 17 00:00:00 2001 From: neodiX Date: Sun, 25 Feb 2024 09:59:47 +0100 Subject: [PATCH 108/236] Clone OpenSSL using tag name instead of branch name --- mytonctrl/scripts/upgrade.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index 408b1cbb..b5f3c8ed 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -52,10 +52,10 @@ fi rm -rf ${bindir}/openssl_3 git clone https://github.com/openssl/openssl ${bindir}/openssl_3 cd ${bindir}/openssl_3 +git checkout openssl-3.1.4 ./config make build_libs -j$(nproc) opensslPath=`pwd` -git checkout openssl-3.1.4 # Go to work dir cd ${srcdir} From adaf7047065861339ec7349cfe0904e17a75ed44 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 27 Feb 2024 12:25:14 +0700 Subject: [PATCH 109/236] add offers garbage collector --- mytoncore/mytoncore.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index a92eb1bd..723bc685 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2950,13 +2950,22 @@ def WriteBookmarkData(self, bookmark): bookmark["data"] = data #end define + def offers_gc(self, save_offers): + current_offers = self.GetOffers() + current_offers_hashes = [offer.get("hash") for offer in current_offers] + for offer in save_offers: + if offer not in current_offers_hashes: + save_offers.pop(offer) + return save_offers + def GetSaveOffers(self): bname = "saveOffers" - saveOffers = self.local.db.get(bname) - if saveOffers is None: - saveOffers = dict() - self.local.db[bname] = saveOffers - return saveOffers + save_offers = self.local.db.get(bname) + if save_offers is None: + save_offers = dict() + self.local.db[bname] = save_offers + self.offers_gc(save_offers) + return save_offers #end define def AddSaveOffer(self, offer): From 1cb220412201427259db7532977efa9e4eb460a1 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 27 Feb 2024 12:41:06 +0700 Subject: [PATCH 110/236] add deleting old files from temp dir --- mytoncore/mytoncore.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 723bc685..ef50af45 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1495,10 +1495,26 @@ 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=adnl_addr, var1=var1, validatorSignature=validatorSignature, validatorPubkey=validatorPubkey) - self.local.add_log("ElectionEntry completed. Start work time: " + str(startWorkTime)) + + self.clear_tmp() + #end define + def clear_tmp(self): + start = time.time() + count = 0 + dir = self.tempDir + for f in os.listdir(dir): + ts = f.split('_')[0] + if ts.isdigit(): + ts = int(ts) + week = 60 * 60 * 24 * 7 + if ts < time.time() - week: + count += 1 + os.remove(os.path.join(dir, f)) + self.local.add_log(f"Removed {count} old files from tmp dir for {int(time.time() - start)} seconds", "info") + def GetValidatorKeyByTime(self, startWorkTime, endWorkTime): self.local.add_log("start GetValidatorKeyByTime function", "debug") # Check temp key From d19883ab73cc241b32724228e01388359721d907 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 27 Feb 2024 12:48:26 +0700 Subject: [PATCH 111/236] improves --- mytoncore/mytoncore.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index ef50af45..913c4570 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1504,15 +1504,21 @@ def ElectionEntry(self, args=None): def clear_tmp(self): start = time.time() count = 0 + week_ago = 60 * 60 * 24 * 7 dir = self.tempDir for f in os.listdir(dir): - ts = f.split('_')[0] - if ts.isdigit(): - ts = int(ts) - week = 60 * 60 * 24 * 7 - if ts < time.time() - week: + prefix = f.split('_')[0] + if prefix.isdigit(): + ts = int(prefix) + if ts < time.time() - week_ago: count += 1 os.remove(os.path.join(dir, f)) + elif prefix == 'checkload': + ts = int(f.split('_')[1]) + if ts < time.time() - week_ago: + count += 1 + os.remove(os.path.join(dir, f)) + self.local.add_log(f"Removed {count} old files from tmp dir for {int(time.time() - start)} seconds", "info") def GetValidatorKeyByTime(self, startWorkTime, endWorkTime): From cbdd56cd20efb5b7e48e42929f4b043437230091 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 27 Feb 2024 21:20:34 +0700 Subject: [PATCH 112/236] improves --- mytoncore/mytoncore.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 913c4570..5a72fc5b 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1507,17 +1507,10 @@ def clear_tmp(self): week_ago = 60 * 60 * 24 * 7 dir = self.tempDir for f in os.listdir(dir): - prefix = f.split('_')[0] - if prefix.isdigit(): - ts = int(prefix) - if ts < time.time() - week_ago: - count += 1 - os.remove(os.path.join(dir, f)) - elif prefix == 'checkload': - ts = int(f.split('_')[1]) - if ts < time.time() - week_ago: - count += 1 - os.remove(os.path.join(dir, f)) + ts = os.path.getmtime(os.path.join(dir, f)) + if ts < time.time() - week_ago: + count += 1 + os.remove(os.path.join(dir, f)) self.local.add_log(f"Removed {count} old files from tmp dir for {int(time.time() - start)} seconds", "info") From 2742f7b8c046bc1ccd43ca1b632083ecee906d13 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 28 Feb 2024 11:07:46 +0700 Subject: [PATCH 113/236] fix offers gc --- mytoncore/mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 5a72fc5b..bbc73c29 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2968,7 +2968,7 @@ def WriteBookmarkData(self, bookmark): def offers_gc(self, save_offers): current_offers = self.GetOffers() current_offers_hashes = [offer.get("hash") for offer in current_offers] - for offer in save_offers: + for offer in list(save_offers.keys()): if offer not in current_offers_hashes: save_offers.pop(offer) return save_offers From ff977ef206a11f9a6eb0c10fcea08f3c1d3aa08e Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 28 Feb 2024 14:46:11 +0300 Subject: [PATCH 114/236] add ls-proxy installer --- mytoninstaller/config.py | 18 +++- mytoninstaller/mytoninstaller.py | 86 ++++++++++------ mytoninstaller/scripts/ls_proxy_installer.sh | 103 +++++++++++++++++++ mytoninstaller/settings.py | 99 ++++++++++++------ mytoninstaller/utils.py | 65 +++++++----- requirements.txt | 2 +- scripts/install.sh | 4 +- scripts/ton_installer.sh | 19 ++-- setup.py | 83 +++++++-------- 9 files changed, 335 insertions(+), 144 deletions(-) create mode 100644 mytoninstaller/scripts/ls_proxy_installer.sh diff --git a/mytoninstaller/config.py b/mytoninstaller/config.py index c1a78dd2..871e691c 100644 --- a/mytoninstaller/config.py +++ b/mytoninstaller/config.py @@ -5,7 +5,7 @@ import base64 from mytoncore.utils import hex2b64, dict2b64 -from mytoninstaller.utils import StartMytoncore, GetInitBlock +from mytoninstaller.utils import StartMytoncore, GetInitBlock, get_ed25519_pubkey_text from mypylib.mypylib import ip2int, Dict @@ -134,3 +134,19 @@ def GetLiteServerConfig(local): result.id.key= key.decode() return result #end define + +def get_ls_proxy_config(local): + ls_proxy_config_path = "/var/ls_proxy/ls-proxy-config.json" + ls_proxy_config = GetConfig(path=ls_proxy_config_path) + ip = get_own_ip() + port = ls_proxy_config.ListenAddr.split(':')[1] + privkey_text = ls_proxy_config.Clients[0].PrivateKey + + result = Dict() + result.ip = ip2int(ip) + result.port = port + result.id = Dict() + result.id["@type"]= "pub.ed25519" + result.id.key= get_ed25519_pubkey_text(privkey_text) + return result +#end define diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 3400df55..ee542a6f 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -7,29 +7,29 @@ import json import subprocess -from mypylib.mypylib import MyPyClass, run_as_root +from mypylib.mypylib import MyPyClass, run_as_root, color_print from mypyconsole.mypyconsole import MyPyConsole -from mytoninstaller.config import GetLiteServerConfig +from mytoninstaller.config import GetLiteServerConfig, get_ls_proxy_config from mytoninstaller.utils import GetInitBlock from mytoncore.utils import dict2b64, str2bool, b642dict from mytoninstaller.settings import ( - FirstNodeSettings, - FirstMytoncoreSettings, - EnableValidatorConsole, - EnableLiteServer, - EnableDhtServer, - EnableJsonRpc, - EnablePytonv3, + FirstNodeSettings, + FirstMytoncoreSettings, + EnableValidatorConsole, + EnableLiteServer, + EnableDhtServer, + EnableJsonRpc, EnableTonHttpApi, - DangerousRecoveryValidatorConfigFile, - CreateSymlinks, + DangerousRecoveryValidatorConfigFile, + CreateSymlinks, + enable_ls_proxy ) from mytoninstaller.config import ( - CreateLocalConfig, - BackupVconfig, - BackupMconfig, + CreateLocalConfig, + BackupVconfig, + BackupMconfig, ) from functools import partial @@ -62,10 +62,12 @@ def inject_globals(func): 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' - ton-http-api. Example: 'enable FN'") + console.AddItem("enable", inject_globals(Enable), "Enable some function") 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("plsc", inject_globals(PrintLiteServerConfig), "Print lite-server config") + console.AddItem("clcf", inject_globals(CreateLocalConfigFile), "Create lite-server config file") + console.AddItem("print_ls_proxy_config", inject_globals(print_ls_proxy_config), "Print ls-proxy config") + console.AddItem("create_ls_proxy_config_file", inject_globals(create_ls_proxy_config_file), "Create ls-proxy config file") 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") @@ -123,10 +125,22 @@ def Status(local, args): def Enable(local, args): - name = args[0] - if name == "PT": + try: + name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} enable ") + print("'FN' - Full node") + print("'VC' - Validator console") + print("'LS' - Lite-Server") + print("'DS' - DHT-Server") + print("'JR' - jsonrpc") + print("'THA' - ton-http-api") + print("'LSP' - ls-proxy") + print("Example: 'enable FN'") + return + if name == "THA": CreateLocalConfigFile(local, args) - args = ["python3", "-m", "mytoninstaller", "-u", local.buffer.user, "-e", "enable{name}".format(name=name)] + args = ["python3", "-m", "mytoninstaller", "-u", local.buffer.user, "-e", f"enable{name}"] run_as_root(args) #end define @@ -159,6 +173,15 @@ def CreateLocalConfigFile(local, args): run_as_root(args) #end define +def print_ls_proxy_config(local, args): + ls_proxy_config = get_ls_proxy_config(local) + text = json.dumps(ls_proxy_config, indent=4) + print(text) +#end define + +def create_ls_proxy_config_file(local, args): + print("TODO") +#end define def Event(local, name): if name == "enableFN": @@ -173,9 +196,10 @@ def Event(local, name): DangerousRecoveryValidatorConfigFile(local) if name == "enableJR": EnableJsonRpc(local) - if name == "enablePT": - # EnablePytonv3(local) + if name == "enableTHA": EnableTonHttpApi(local) + if name == "enableLSP": + enable_ls_proxy(local) if name == "clc": ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] @@ -219,12 +243,12 @@ def General(local): ### 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() + 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/ls_proxy_installer.sh b/mytoninstaller/scripts/ls_proxy_installer.sh new file mode 100644 index 00000000..16630251 --- /dev/null +++ b/mytoninstaller/scripts/ls_proxy_installer.sh @@ -0,0 +1,103 @@ +#!/bin/bash +set -e + +# Проверить sudo +if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 +fi + +# install parameters +src_path=/usr/src +bin_path=/usr/bin +openssl_path=${bin_path}/openssl_3 + +# Get arguments +while getopts u:s:b:o: flag +do + case "${flag}" in + u) user=${OPTARG};; + s) src_path=${OPTARG};; + b) bin_path=${OPTARG};; + o) openssl_path=${OPTARG};; + *) + echo "Flag -${flag} is not recognized. Aborting" + exit 1;; + esac +done + +# install parameters +author=xssnick +repo=tonutils-liteserver-proxy +branch=master +bin_name=ls_proxy + +# Цвета +COLOR='\033[95m' +ENDC='\033[0m' + +# Клонирование репозиториев с github.com +echo -e "${COLOR}[1/4]${ENDC} Cloning github repository" +echo "https://github.com/${author}/${repo}.git -> ${branch}" + +cd ${src_path} +rm -rf ${repo} +git clone --branch=${branch} --recursive https://github.com/${author}/${repo}.git + +# Установка компонентов +echo -e "${COLOR}[2/4]${ENDC} Installing required packages" + +arc=$(dpkg --print-architecture) +go_version_url=https://go.dev/VERSION?m=text +go_version=$(curl -s ${go_version_url} | head -n 1) +go_url=https://go.dev/dl/${go_version}.linux-${arc}.tar.gz +go_path=/usr/local/go/bin/go +rm -rf /usr/local/go +wget -c ${go_url} -O - | tar -C /usr/local -xz + +# Расчитываем количество процессоров для сборки +if [[ "$OSTYPE" =~ darwin.* ]]; then + cpu_number=$(sysctl -n hw.logicalcpu) +else + memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') + cpu_number=$(($memory/2100000)) + max_cpu_number=$(nproc) + if [ ${cpu_number} -gt ${max_cpu_number} ]; then + cpu_number=$((${max_cpu_number}-1)) + fi + if [ ${cpu_number} == 0 ]; then + echo "Warning! insufficient RAM" + cpu_number=1 + fi +fi + +# Компилируем из исходников +echo -e "${COLOR}[3/4]${ENDC} Source compilation, use ${cpu_number} cpus" + +proxy_src_path=${src_path}/${repo} +ton_src_path=${proxy_src_path}/ton +proxy_internal_path=${proxy_src_path}/internal/emulate/lib + +proxy_build_path=${bin_path}/${bin_name} +ton_build_path=${proxy_build_path}/ton +proxy_db_path=/var/${bin_name} +proxy_lib_path=${proxy_db_path}/lib + +mkdir -p ${proxy_lib_path} +mkdir -p ${ton_build_path} && cd ${ton_build_path} +cmake -DCMAKE_BUILD_TYPE=Release -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=${openssl_path}/include -DOPENSSL_CRYPTO_LIBRARY=${openssl_path}/libcrypto.a ${ton_src_path} +make emulator -j ${cpu_number} +cp ${ton_build_path}/emulator/libemulator.so ${proxy_lib_path} +cp ${ton_build_path}/emulator/libemulator.so ${proxy_internal_path} +cp ${ton_build_path}/emulator/emulator_export.h ${proxy_internal_path} + +# Компилируем +cd ${proxy_src_path} +CGO_ENABLED=1 ${go_path} build -o ${proxy_db_path}/${bin_name} ${proxy_src_path}/cmd/main.go + +# Настроить директорию работы +chown -R ${user}:${user} ${proxy_db_path} + +# Выход из программы +echo -e "${COLOR}[4/4]${ENDC} ${bin_name} installation complete" +exit 0 diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 60e3e211..f1c73a4f 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -1,6 +1,7 @@ import os import os.path import psutil +import base64 import subprocess import requests import random @@ -15,7 +16,7 @@ ip2int, Dict ) -from mytoninstaller.utils import StartValidator, StartMytoncore +from mytoninstaller.utils import StartValidator, StartMytoncore, start_service, stop_service, get_ed25519_pubkey from mytoninstaller.config import SetConfig, GetConfig, get_own_ip from mytoncore.utils import hex2b64 @@ -428,8 +429,7 @@ def EnableDhtServer(local): subprocess.run(args) # start DHT-Server - args = ["systemctl", "restart", "dht-server"] - subprocess.run(args) + start_service(local, "dht-server") #end define @@ -447,22 +447,6 @@ def EnableJsonRpc(local): color_print(text) #end define - -def EnablePytonv3(local): - local.add_log("start EnablePytonv3 function", "debug") - user = local.buffer.user - - 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 EnableTonHttpApi(local): local.add_log("start EnablePytonv3 function", "debug") user = local.buffer.user @@ -474,17 +458,70 @@ def EnableTonHttpApi(local): else: text = "EnableTonHttpApi - {red}Error{endc}" color_print(text) +#end define + +def enable_ls_proxy(local): + local.add_log("start enable_ls_proxy function", "debug") + user = local.buffer.user + ls_proxy_port = random.randint(2000, 65000) + metrics_port = random.randint(2000, 65000) + bin_name = "ls_proxy" + ls_proxy_db_path = f"/var/{bin_name}" + ls_proxy_path = f"{ls_proxy_db_path}/{bin_name}" + ls_proxy_config_path = f"{ls_proxy_db_path}/ls-proxy-config.json" + + installer_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'ls_proxy_installer.sh') + local.add_log(f"Running script: {installer_path}", "debug") + exitCode = run_as_root(["bash", installer_path, "-u", user]) + if exitCode != 0: + color_print("enable_ls_proxy - {red}Error{endc}") + #end if + + # Прописать автозагрузку + add2systemd(name=bin_name, user=user, start=ls_proxy_path, workdir=ls_proxy_db_path) + # Первый запуск - создание конфига + start_service(local, bin_name) + stop_service(local, bin_name) + + # read ls_proxy config + local.add_log("read ls_proxy config", "debug") + ls_proxy_config = GetConfig(path=ls_proxy_config_path) + + # read mytoncore config + local.add_log("read mytoncore config", "debug") + mconfig = GetConfig(path=local.buffer.mconfig_path) + ls_pubkey_path = mconfig.liteClient.liteServer.pubkeyPath + ls_port = mconfig.liteClient.liteServer.port + + # read ls_pubkey + with open(ls_pubkey_path, 'rb') as file: + data = file.read() + pubkey = data[4:] + ls_pubkey = base64.b64encode(pubkey).decode("utf-8") + #end with + + # prepare config + ls_proxy_config.ListenAddr = f"0.0.0.0:{ls_proxy_port}" + ls_proxy_config.MetricsAddr = f"127.0.0.1:{metrics_port}" + ls_proxy_config.Backends = [{ + "Name": "local_ls", + "Addr": f"127.0.0.1:{ls_port}", + "Key": ls_pubkey + }] + + # write ls_proxy config + local.add_log("write ls_proxy config", "debug") + SetConfig(path=ls_proxy_config_path, data=ls_proxy_config) + + # start ls_proxy + start_service(local, bin_name) + color_print("enable_ls_proxy - {green}OK{endc}") +#end define def DangerousRecoveryValidatorConfigFile(local): local.add_log("start DangerousRecoveryValidatorConfigFile function", "info") - # install and import cryptography library - args = ["pip3", "install", "cryptography"] - subprocess.run(args) - from cryptography.hazmat.primitives import serialization - from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - # Get keys from keyring keys = list() keyringDir = "/var/ton-work/db/keyring/" @@ -528,10 +565,8 @@ def DangerousRecoveryValidatorConfigFile(local): file = open(path, 'rb') data = file.read() file.close() - peivkey = data[4:] - privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) - pubkeyObject = privkeyObject.public_key() - pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) + privkey = data[4:] + pubkey = get_ed25519_pubkey(privkey) if pubkey == ls_pubkey: ls_id = hex2b64(item) keys.remove(ls_id) @@ -562,10 +597,8 @@ def DangerousRecoveryValidatorConfigFile(local): file = open(path, 'rb') data = file.read() file.close() - peivkey = data[4:] - privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) - pubkeyObject = privkeyObject.public_key() - pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) + privkey = data[4:] + pubkey = get_ed25519_pubkey(privkey) if pubkey == vPubkey: vcId = hex2b64(item) keys.remove(vcId) diff --git a/mytoninstaller/utils.py b/mytoninstaller/utils.py index c811f158..a2cd817f 100644 --- a/mytoninstaller/utils.py +++ b/mytoninstaller/utils.py @@ -2,34 +2,51 @@ import json import time import subprocess +from nacl.signing import SigningKey def GetInitBlock(): - from mypylib.mypylib import MyPyClass - from mytoncore import MyTonCore - - mytoncore_local = MyPyClass('mytoncore.py') - ton = MyTonCore(mytoncore_local) - initBlock = ton.GetInitBlock() - return initBlock -# end define - + from mypylib.mypylib import MyPyClass + from mytoncore import MyTonCore + + mytoncore_local = MyPyClass('mytoncore.py') + ton = MyTonCore(mytoncore_local) + initBlock = ton.GetInitBlock() + return initBlock +#end define + +def start_service(local, service_name:str, sleep:int=1): + local.add_log(f"Start/restart {service_name} service", "debug") + args = ["systemctl", "restart", service_name] + subprocess.run(args) + + local.add_log(f"sleep {sleep} sec", "debug") + time.sleep(sleep) +#end define + +def stop_service(local, service_name:str): + local.add_log(f"Stop {service_name} service", "debug") + args = ["systemctl", "stop", service_name] + subprocess.run(args) +#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 - + start_service(local, "validator", 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 + start_service(local, "mytoncore") +#end define + +def get_ed25519_pubkey_text(privkey_text): + privkey = base64.b64decode(privkey_text) + pubkey = get_ed25519_pubkey(privkey) + pubkey_text = base64.b64encode(pubkey).decode("utf-8") + return pubkey_text +#end define + +def get_ed25519_pubkey(privkey): + privkey_obj = SigningKey(privkey) + pubkey = privkey_obj.verify_key.encode() + return pubkey +#end define diff --git a/requirements.txt b/requirements.txt index 22953b42..f7705c47 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ crc16 requests psutil -cryptography fastcrc jsonpickle +pynacl diff --git a/scripts/install.sh b/scripts/install.sh index 79e1f316..b57b9453 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -106,7 +106,7 @@ cd $SOURCES_DIR/${repo} pip3 install -U . # TODO: make installation from git directly -echo -e "${COLOR}[3/5]${ENDC} Running mytoninstaller" +echo -e "${COLOR}[4/5]${ENDC} Running mytoninstaller" # DEBUG parent_name=$(ps -p $PPID -o comm=) @@ -125,5 +125,5 @@ mkdir -p ${version_dir} echo ${migrate_version} > ${version_path} chown ${user}:${user} ${version_dir} ${version_path} -echo -e "${COLOR}[4/4]${ENDC} Mytonctrl installation completed" +echo -e "${COLOR}[5/5]${ENDC} Mytonctrl installation completed" exit 0 diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 9f053379..95a0c334 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -134,21 +134,24 @@ else cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a fi -# Компилируем из исходников -echo -e "${COLOR}[4/6]${ENDC} Source Compilation" +# Расчитываем количество процессоров для сборки if [[ "$OSTYPE" =~ darwin.* ]]; then - cpuNumber=$(sysctl -n hw.logicalcpu) + cpu_number=$(sysctl -n hw.logicalcpu) else memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') - cpuNumber=$(cat /proc/cpuinfo | grep "processor" | wc -l) - if [ ${cpuNumber} == 0 ]; then + cpu_number=$(($memory/2100000)) + max_cpu_number=$(nproc) + if [ ${cpu_number} -gt ${max_cpu_number} ]; then + cpu_number=$((${max_cpu_number}-1)) + fi + if [ ${cpu_number} == 0 ]; then echo "Warning! insufficient RAM" - cpuNumber=1 + cpu_number=1 fi fi -echo "use ${cpuNumber} cpus" -ninja -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy +echo -e "${COLOR}[4/6]${ENDC} Source compilation, use ${cpu_number} cpus" +ninja -j ${cpu_number} fift validator-engine lite-client 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/setup.py b/setup.py index 1d991cca..c4302d88 100644 --- a/setup.py +++ b/setup.py @@ -2,53 +2,48 @@ from os.path import dirname, join with open(join(dirname(__file__), "README.md"), "r") as f: - long_description = f.read() + long_description = f.read() +with open(join(dirname(__file__), "requirements.txt")) as file: + install_requires = file.read().split('\n') version = 'v0.1' setup( - author='igroman787', - author_email='igroman787', - name='mytonctrl', - version=version, - packages=find_packages('.', exclude=['tests']), - install_requires=[ - 'crc16', - 'requests', - 'psutil', - 'cryptography', - 'fastcrc', - 'jsonpickle', - ], - package_data={ - 'mytoninstaller.scripts': ['*.sh'], - 'mytoncore': [ - 'contracts/**/*', - 'complaints/*' - ], - 'mytonctrl': [ - 'resources/*', - 'scripts/*', - 'migrations/*.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", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "License :: Other/Proprietary License", - "Topic :: Software Development :: Libraries" - ], - url="https://github.com/ton-blockchain/mytonctrl", - description="MyTonCtrl", - long_description_content_type="text/markdown", - long_description=long_description, + author='igroman787', + author_email='igroman787', + name='mytonctrl', + version=version, + packages=find_packages('.', exclude=['tests']), + install_requires=install_requires, + package_data={ + 'mytoninstaller.scripts': ['*.sh'], + 'mytoncore': [ + 'contracts/**/*', + 'complaints/*' + ], + 'mytonctrl': [ + 'resources/*', + 'scripts/*', + 'migrations/*.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", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "License :: Other/Proprietary License", + "Topic :: Software Development :: Libraries" + ], + url="https://github.com/ton-blockchain/mytonctrl", + description="MyTonCtrl", + long_description_content_type="text/markdown", + long_description=long_description, ) From 4c1243c8392aa10f637e73087d08f3b252179561 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 29 Feb 2024 12:33:41 +0700 Subject: [PATCH 115/236] improve save_offers db storage --- mytoncore/mytoncore.py | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index bbc73c29..ba769aee 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2043,6 +2043,11 @@ def GetSaveElectionEntries(self, electionId): return result #end define + def calculate_offer_pseudohash(self, offer_hash: str, param_id: int): + config_val = self.GetConfig(param_id) + pseudohash_bytes = offer_hash.encode() + json.dumps(config_val, sort_keys=True).encode() + return hashlib.sha256(pseudohash_bytes).hexdigest() + def GetOffers(self): self.local.add_log("start GetOffers function", "debug") fullConfigAddr = self.GetFullConfigAddr() @@ -2087,9 +2092,7 @@ def GetOffers(self): item["approvedPercent"] = round(availableWeight / totalWeight * 100, 3) item["isPassed"] = (weightRemaining < 0) #item["pseudohash"] = hashlib.sha256(param_val.encode()).hexdigest() - config_val = self.GetConfig(param_id) - pseudohash_bytes = hash.encode() + json.dumps(config_val, sort_keys=True).encode() - item["pseudohash"] = hashlib.sha256(pseudohash_bytes).hexdigest() + item['pseudohash'] = self.calculate_offer_pseudohash(hash, param_id) offers.append(item) #end for return offers @@ -2345,7 +2348,7 @@ def VoteOffer(self, offerHash): resultFilePath = self.SignProposalVoteRequestWithValidator(offerHash, validatorIndex, validatorPubkey_b64, validatorSignature) resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, fullConfigAddr, 1.5) self.SendFile(resultFilePath, wallet) - self.AddSaveOffer(offer) + self.add_save_offer(offer) #end define def VoteComplaint(self, electionId, complaintHash): @@ -2968,9 +2971,14 @@ def WriteBookmarkData(self, bookmark): def offers_gc(self, save_offers): current_offers = self.GetOffers() current_offers_hashes = [offer.get("hash") for offer in current_offers] - for offer in list(save_offers.keys()): - if offer not in current_offers_hashes: - save_offers.pop(offer) + for offer_hash, offer in list(save_offers.items()): + if offer_hash not in current_offers_hashes: + if isinstance(offer, list): + param_id = offer[1] + if offer[0] != self.calculate_offer_pseudohash(offer_hash, param_id): # param has been changed so no need to keep anymore + save_offers.pop(offer) + else: # old version of offer in db + save_offers.pop(offer) return save_offers def GetSaveOffers(self): @@ -2983,12 +2991,12 @@ def GetSaveOffers(self): return save_offers #end define - def AddSaveOffer(self, offer): - offerHash = offer.get("hash") - offerPseudohash = offer.get("pseudohash") - saveOffers = self.GetSaveOffers() - if offerHash not in saveOffers: - saveOffers[offerHash] = offerPseudohash + def add_save_offer(self, offer): + offer_hash = offer.get("hash") + offer_pseudohash = offer.get("pseudohash") + save_offers = self.GetSaveOffers() + if offer_hash not in save_offers: + save_offers[offer_hash] = [offer_pseudohash, offer.get('config', {}).get("id")] self.local.save() #end define From 229adf190e478e3c6114fb02d7b346f5e7a5a491 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 29 Feb 2024 12:38:41 +0700 Subject: [PATCH 116/236] bugfix --- mytoncore/mytoncore.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index ba769aee..a7e0df54 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2975,7 +2975,8 @@ def offers_gc(self, save_offers): if offer_hash not in current_offers_hashes: if isinstance(offer, list): param_id = offer[1] - if offer[0] != self.calculate_offer_pseudohash(offer_hash, param_id): # param has been changed so no need to keep anymore + if param_id is not None and offer[0] != self.calculate_offer_pseudohash(offer_hash, param_id): + # param has been changed so no need to keep anymore save_offers.pop(offer) else: # old version of offer in db save_offers.pop(offer) From 319be9a04d0d7cb184671c4f23ce43a46084c0f1 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 29 Feb 2024 13:27:17 +0700 Subject: [PATCH 117/236] bugfix --- mytoncore/mytoncore.py | 104 +++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 34759285..a6d0765c 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1292,6 +1292,7 @@ def ProcessRecoverStake(self): def GetStake(self, account, args=None): stake = self.local.db.get("stake") usePool = self.local.db.get("usePool") + useController = self.local.db.get("useController") stakePercent = self.local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() validators = vconfig.get("validators") @@ -1408,6 +1409,7 @@ def GetValidatorWallet(self, mode="stake"): def ElectionEntry(self, args=None): usePool = self.local.db.get("usePool") + useController = self.local.db.get("useController") wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 if wallet is None: @@ -1500,9 +1502,9 @@ def ElectionEntry(self, args=None): resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, pool.addrB64, 1.3) self.SendFile(resultFilePath, wallet) elif useController: - var1 = self.CreateElectionRequest(controllerAddr, startWorkTime, adnlAddr, maxFactor) + var1 = self.CreateElectionRequest(controllerAddr, startWorkTime, adnl_addr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) - validatorPubkey, resultFilePath = self.SignElectionRequestWithController(controllerAddr, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake) + validatorPubkey, resultFilePath = self.SignElectionRequestWithController(controllerAddr, startWorkTime, adnl_addr, validatorPubkey_b64, validatorSignature, maxFactor, stake) # Send boc file to TON resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, controllerAddr, 1.03) @@ -3691,7 +3693,7 @@ def GetPoolData(self, addrB64): #end define def GetLiquidPoolAddr(self): - liquid_pool_addr = local.db.get("liquid_pool_addr") + liquid_pool_addr = self.local.db.get("liquid_pool_addr") if liquid_pool_addr is None: raise Exception("GetLiquidPoolAddr error: liquid_pool_addr not set") return liquid_pool_addr @@ -3699,12 +3701,12 @@ def GetLiquidPoolAddr(self): def CreateControllers(self): new_controllers = self.GetControllers() - old_controllers = local.db.get("using_controllers", list()) + old_controllers = self.local.db.get("using_controllers", list()) if new_controllers == old_controllers: return #end if - local.add_log("start CreateControllers function", "debug") + self.local.add_log("start CreateControllers function", "debug") wallet = self.GetValidatorWallet() liquid_pool_addr = self.GetLiquidPoolAddr() contractPath = self.contractsDir + "jetton_pool/" @@ -3721,9 +3723,9 @@ def CreateControllers(self): self.SendFile(resultFilePath1, wallet) # Сохранить новые контроллеры - local.db["old_controllers"] = old_controllers - local.db["using_controllers"] = new_controllers - local.save() + self.local.db["old_controllers"] = old_controllers + self.local.db["using_controllers"] = new_controllers + self.local.save() #end define def GetControllerAddress(self, controller_id): @@ -3741,9 +3743,9 @@ def GetControllerAddress(self, controller_id): #end define def CheckController(self, controllerAddr): - local.add_log("start CheckController function", "debug") + self.local.add_log("start CheckController function", "debug") controllerData = self.GetControllerData(controllerAddr) - using_controllers = local.db.get("using_controllers", list()) + using_controllers = self.local.db.get("using_controllers", list()) if controllerData is None: raise Exception(f"CheckController error: controller not initialized. Use new_controllers") if controllerData["approved"] != -1: @@ -3753,7 +3755,7 @@ def CheckController(self, controllerAddr): #end define def GetControllers(self): - local.add_log("start GetControllers function", "debug") + self.local.add_log("start GetControllers function", "debug") controller0 = self.GetControllerAddress(controller_id=0) controller1 = self.GetControllerAddress(controller_id=1) controllers = [controller0, controller1] @@ -3782,10 +3784,10 @@ def GetControllerRequiredBalanceForLoan(self, controllerAddr, credit, interest): #end define def IsControllerReadyToStake(self, addrB64): - stop_controllers_list = local.db.get("stop_controllers_list") + stop_controllers_list = self.local.db.get("stop_controllers_list") if stop_controllers_list is not None and addrB64 in stop_controllers_list: return False - now = GetTimestamp() + now = get_timestamp() config15 = self.GetConfig15() controllerData = self.GetControllerData(addrB64) if controllerData is None: @@ -3817,16 +3819,16 @@ def GetControllerData(self, controllerAddr): #end define def CreateLoanRequest(self, controllerAddr): - local.add_log("start CreateLoanRequest function", "debug") - min_loan = local.db.get("min_loan", 41000) - max_loan = local.db.get("max_loan", 43000) - max_interest_percent = local.db.get("max_interest_percent", 1.5) + self.local.add_log("start CreateLoanRequest function", "debug") + min_loan = self.local.db.get("min_loan", 41000) + max_loan = self.local.db.get("max_loan", 43000) + max_interest_percent = self.local.db.get("max_interest_percent", 1.5) max_interest = int(max_interest_percent/100*16777216) # Проверить наличие действующего кредита controllerData = self.GetControllerData(controllerAddr) if controllerData["borrowed_amount"] > 0: - local.add_log("CreateLoanRequest warning: past loan found", "warning") + self.local.add_log("CreateLoanRequest warning: past loan found", "warning") return #end define @@ -3873,15 +3875,15 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): #end define def CalculateLoanAmount_test(self): - min_loan = local.db.get("min_loan", 41000) - max_loan = local.db.get("max_loan", 43000) - max_interest_percent = local.db.get("max_interest_percent", 1.5) + min_loan = self.local.db.get("min_loan", 41000) + max_loan = self.local.db.get("max_loan", 43000) + max_interest_percent = self.local.db.get("max_interest_percent", 1.5) max_interest = int(max_interest_percent/100*16777216) return self.CalculateLoanAmount(min_loan, max_loan, max_interest) #end define def WaitLoan(self, controllerAddr): - local.add_log("start WaitLoan function", "debug") + self.local.add_log("start WaitLoan function", "debug") for i in range(10): time.sleep(3) controllerData = self.GetControllerData(controllerAddr) @@ -3891,7 +3893,7 @@ def WaitLoan(self, controllerAddr): #end define def ReturnUnusedLoan(self, controllerAddr): - local.add_log("start ReturnUnusedLoan function", "debug") + self.local.add_log("start ReturnUnusedLoan function", "debug") wallet = self.GetValidatorWallet() fileName = self.contractsDir + "jetton_pool/fift-scripts/return_unused_loan.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.05) @@ -3899,7 +3901,7 @@ def ReturnUnusedLoan(self, controllerAddr): #end define def DepositToController(self, controllerAddr, amount): - local.add_log("start DepositToController function", "debug") + self.local.add_log("start DepositToController function", "debug") wallet = self.GetValidatorWallet() fileName = self.contractsDir + "jetton_pool/fift-scripts/top-up.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, amount) @@ -3922,7 +3924,7 @@ def WithdrawFromControllerProcess(self, controllerAddr, amount): return #end if - local.add_log("start WithdrawFromControllerProcess function", "debug") + self.local.add_log("start WithdrawFromControllerProcess function", "debug") wallet = self.GetValidatorWallet() fiftScript = self.contractsDir + "jetton_pool/fift-scripts/withdraw-controller.fif" resultFilePath = self.tempDir + self.nodeName + wallet.name + "_withdraw_request.boc" @@ -3933,10 +3935,10 @@ def WithdrawFromControllerProcess(self, controllerAddr, amount): #end define def PendWithdrawFromController(self, controllerAddr, amount): - local.add_log("start PendWithdrawFromController function", "debug") + self.local.add_log("start PendWithdrawFromController function", "debug") controllerPendingWithdraws = self.GetControllerPendingWithdraws() controllerPendingWithdraws[controllerAddr] = amount - local.save() + self.local.save() #end define def HandleControllerPendingWithdraw(self, controllerPendingWithdraws, controllerAddr): @@ -3947,37 +3949,37 @@ def HandleControllerPendingWithdraw(self, controllerPendingWithdraws, controller def GetControllerPendingWithdraws(self): bname = "controllerPendingWithdraws" - controllerPendingWithdraws = local.db.get(bname) + controllerPendingWithdraws = self.local.db.get(bname) if controllerPendingWithdraws is None: controllerPendingWithdraws = dict() - local.db[bname] = controllerPendingWithdraws + self.local.db[bname] = controllerPendingWithdraws return controllerPendingWithdraws #end define def SignElectionRequestWithController(self, controllerAddr, startWorkTime, adnlAddr, validatorPubkey_b64, validatorSignature, maxFactor, stake): - local.add_log("start SignElectionRequestWithController function", "debug") + self.local.add_log("start SignElectionRequestWithController function", "debug") fileName = self.tempDir + str(startWorkTime) + "_validator-query.boc" fiftScript = self.contractsDir + "jetton_pool/fift-scripts/controller-elect-signed.fif" args = [fiftScript, controllerAddr, startWorkTime, maxFactor, adnlAddr, validatorPubkey_b64, validatorSignature, fileName, stake] - local.add_log(f"SignElectionRequestWithController args: {args}", "debug") + self.local.add_log(f"SignElectionRequestWithController args: {args}", "debug") result = self.fift.Run(args) - local.add_log(f"SignElectionRequestWithController result: {result}", "debug") - pubkey = Pars(result, "validator public key ", '\n') - fileName = Pars(result, "Saved to file ", '\n') + self.local.add_log(f"SignElectionRequestWithController result: {result}", "debug") + pubkey = parse(result, "validator public key ", '\n') + fileName = parse(result, "Saved to file ", '\n') return pubkey, fileName #end define def ControllersUpdateValidatorSet(self): - local.add_log("start ControllersUpdateValidatorSet function", "debug") - using_controllers = local.db.get("using_controllers") - user_controllers = local.db.get("user_controllers", list()) - old_controllers = local.db.get("old_controllers", list()) + self.local.add_log("start ControllersUpdateValidatorSet function", "debug") + using_controllers = self.local.db.get("using_controllers") + user_controllers = self.local.db.get("user_controllers", list()) + old_controllers = self.local.db.get("old_controllers", list()) for controller in using_controllers + user_controllers + old_controllers: self.ControllerUpdateValidatorSet(controller) #end define def ControllerUpdateValidatorSet(self, controllerAddr): - local.add_log("start ControllerUpdateValidatorSet function", "debug") + self.local.add_log("start ControllerUpdateValidatorSet function", "debug") wallet = self.GetValidatorWallet() controllers = self.GetControllers() controllerData = self.GetControllerData(controllerAddr) @@ -4012,48 +4014,48 @@ def ControllerUpdateValidatorSet(self, controllerAddr): #end define def ControllerUpdateValidatorSetProcess(self, controllerAddr, wallet): - local.add_log("start ControllerUpdateValidatorSetProcess function", "debug") + self.local.add_log("start ControllerUpdateValidatorSetProcess function", "debug") fileName = self.contractsDir + "jetton_pool/fift-scripts/update_validator_hash.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.07) self.SendFile(resultFilePath, wallet) - local.add_log("ControllerUpdateValidatorSetProcess completed") + self.local.add_log("ControllerUpdateValidatorSetProcess completed") #end define def ControllerRecoverStake(self, controllerAddr): wallet = self.GetValidatorWallet() - local.add_log("start ControllerRecoverStake function", "debug") + self.local.add_log("start ControllerRecoverStake function", "debug") fileName = self.contractsDir + "jetton_pool/fift-scripts/recover_stake.boc" resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, 1.04) self.SendFile(resultFilePath, wallet) - local.add_log("ControllerRecoverStake completed") + self.local.add_log("ControllerRecoverStake completed") #end define def StopController(self, controllerAddr): - stop_controllers_list = local.db.get("stop_controllers_list") + stop_controllers_list = self.local.db.get("stop_controllers_list") if stop_controllers_list is None: stop_controllers_list = list() if controllerAddr not in stop_controllers_list: stop_controllers_list.append(controllerAddr) - local.db["stop_controllers_list"] = stop_controllers_list + self.local.db["stop_controllers_list"] = stop_controllers_list - user_controllers = local.db.get("user_controllers") + user_controllers = self.local.db.get("user_controllers") if user_controllers is not None and controllerAddr in user_controllers: user_controllers.remove(controllerAddr) - local.save() + self.local.save() #end define def AddController(self, controllerAddr): - user_controllers = local.db.get("user_controllers") + user_controllers = self.local.db.get("user_controllers") if user_controllers is None: user_controllers = list() if controllerAddr not in user_controllers: user_controllers.append(controllerAddr) - local.db["user_controllers"] = user_controllers + self.local.db["user_controllers"] = user_controllers - stop_controllers_list = local.db.get("stop_controllers_list") + stop_controllers_list = self.local.db.get("stop_controllers_list") if stop_controllers_list is not None and controllerAddr in stop_controllers_list: stop_controllers_list.remove(controllerAddr) - local.save() + self.local.save() #end define def CheckLiquidPool(self): From 0db8293c14fda61f1b2e73fa594514f887cf220e Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 29 Feb 2024 13:57:48 +0700 Subject: [PATCH 118/236] add controllecrs to mytonctrl.py --- mytonctrl/mytonctrl.py | 153 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index b4a7768a..2b47e6a6 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -138,6 +138,20 @@ def inject_globals(func): console.AddItem("activate_single_pool", inject_globals(activate_single_pool), local.translate("activate_single_pool_cmd")) console.AddItem("import_pool", inject_globals(import_pool), local.translate("import_pool_cmd")) + console.AddItem("create_controllers", inject_globals(CreateControllers), local.translate("_")) + console.AddItem("update_controllers", inject_globals(CreateControllers), local.translate("_")) + console.AddItem("controllers_list", inject_globals(PrintControllersList), local.translate("_")) + console.AddItem("get_controller_data", inject_globals(GetControllerData), local.translate("_")) + console.AddItem("deposit_to_controller", inject_globals(DepositToController), local.translate("_")) + console.AddItem("withdraw_from_controller", inject_globals(WithdrawFromController), local.translate("_")) + console.AddItem("calculate_annual_controller_percentage", inject_globals(CalculateAnnualControllerPercentage), local.translate("_")) + console.AddItem("controller_update_validator_set", inject_globals(ControllerUpdateValidatorSet), local.translate("_")) + console.AddItem("stop_controller", inject_globals(StopController), local.translate("_")) + console.AddItem("stop_and_withdraw_controller", inject_globals(StopAndWithdrawController), local.translate("_")) + console.AddItem("add_controller", inject_globals(AddController), local.translate("_")) + console.AddItem("check_liquid_pool", inject_globals(CheckLiquidPool), local.translate("_")) + console.AddItem("test_calculate_loan_amount", inject_globals(CalculateLoanAmount_test), local.translate("_")) + # console.AddItem("pt", inject_globals(PrintTest), "PrintTest") # console.AddItem("sl", inject_globals(sl), "sl") console.AddItem("cleanup", inject_globals(cleanup_validator_db), local.translate("cleanup_cmd")) @@ -1489,6 +1503,145 @@ def import_pool(ton, args): color_print("import_pool - {green}OK{endc}") #end define +def CreateControllers(ton, args): + ton.CreateControllers() + color_print("CreateControllers - {green}OK{endc}") +#end define + +def PrintControllersList(ton, args): + new_controllers = ton.GetControllers() + using_controllers = ton.GetSettings("using_controllers") + old_controllers = ton.GetSettings("old_controllers") + user_controllers_list = ton.GetSettings("user_controllers_list") + print("using controllers:") + PrintControllersListProcess(ton, using_controllers) + if new_controllers != using_controllers: + print() + print("new controllers:") + PrintControllersListProcess(ton, new_controllers) + if old_controllers is not None and len(old_controllers) > 0: + print() + print("old controllers:") + PrintControllersListProcess(ton, old_controllers) + if user_controllers_list is not None and len(user_controllers_list) > 0: + print() + print("user controllers:") + PrintControllersListProcess(ton, user_controllers_list) +#end define + +def PrintControllersListProcess(ton, controllers): + table = list() + table += [["Address", "Status", "Balance", "Approved", "State"]] + for controllerAddr in controllers: + account = ton.GetAccount(controllerAddr) + controllerData = ton.GetControllerData(controllerAddr) + approved = True if controllerData and controllerData["approved"] == -1 else False + state = controllerData["state"] if controllerData else None + table += [[controllerAddr, account.status, account.balance, approved, state]] + print_table(table) +#end define + +def GetControllerData(ton, args): + try: + controllerAddr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} get_controller_data ") + return + controllerData = ton.GetControllerData(controllerAddr) + print(json.dumps(controllerData, indent=4)) +#end define + +def DepositToController(ton, args): + try: + controllerAddr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} deposit_to_controller ") + return + ton.DepositToController(controllerAddr, amount) +#end define + +def WithdrawFromController(ton, args): + try: + controllerAddr = args[0] + amount = GetItemFromList(args, 1) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") + return + ton.WithdrawFromController(controllerAddr, amount) +#end define + +def CalculateAnnualControllerPercentage(ton, args): + try: + percentPerRound = float(args[0]) + except: + percentPerRound = ton.GetSettings("max_interest_percent") + config15 = ton.GetConfig(15) + roundPeriod = config15["validators_elected_for"] + rounds = 365 * 24 * 3600 / roundPeriod + yearInterest = (1 + percentPerRound / 100) * rounds + yearInterestPercent = round(yearInterest / 100, 2) + print("roundPeriod", roundPeriod) + print("rounds", rounds) + print("percentPerRound", percentPerRound) + print("yearInterest", yearInterest) + print(f"yearInterestPercent: {yearInterestPercent}%") +#end define + +def ControllerUpdateValidatorSet(ton, args): + try: + controllerAddr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} controller_update_validator_set ") + return + ton.ControllerUpdateValidatorSet(controllerAddr) + color_print("ControllerUpdateValidatorSet - {green}OK{endc}") +#end define + +def StopController(ton, args): + try: + controllerAddr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} stop_controller ") + return + ton.StopController(controllerAddr) + color_print("StopController - {green}OK{endc}") +#end define + +def StopAndWithdrawController(ton, args): + try: + controllerAddr = args[0] + amount = GetItemFromList(args, 1) + except: + color_print("{red}Bad args. Usage:{endc} stop_and_withdraw_controller [amount]") + return + if amount is None: + account = ton.GetAccount(controllerAddr) + amount = account.balance-10.1 + ton.StopController(controllerAddr) + ton.WithdrawFromController(controllerAddr, amount) + color_print("StopAndWithdrawController - {green}OK{endc}") +#end define + +def AddController(ton, args): + try: + controllerAddr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} add_controller ") + return + ton.AddController(controllerAddr) + color_print("AddController - {green}OK{endc}") +#end define + +def CheckLiquidPool(ton, args): + ton.CheckLiquidPool() + color_print("CheckLiquidPool - {green}OK{endc}") +#end define + +def CalculateLoanAmount_test(ton, args): + t = ton.CalculateLoanAmount_test() + print(t) + ### ### Start of the program From 8bb9d4eae2e879cbd7f656086766f883795f52cb Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 29 Feb 2024 21:00:11 +0700 Subject: [PATCH 119/236] fix typo --- mytoncore/mytoncore.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index a7e0df54..6f90be3f 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2977,9 +2977,9 @@ def offers_gc(self, save_offers): param_id = offer[1] if param_id is not None and offer[0] != self.calculate_offer_pseudohash(offer_hash, param_id): # param has been changed so no need to keep anymore - save_offers.pop(offer) + save_offers.pop(offer_hash) else: # old version of offer in db - save_offers.pop(offer) + save_offers.pop(offer_hash) return save_offers def GetSaveOffers(self): From a4969d6bf6fafd05bc89cafdd0ce6817a3467983 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 1 Mar 2024 11:52:48 +0300 Subject: [PATCH 120/236] Delete mytoninstaller.py --- mytoninstaller.py | 1051 --------------------------------------------- 1 file changed, 1051 deletions(-) delete mode 100644 mytoninstaller.py diff --git a/mytoninstaller.py b/mytoninstaller.py deleted file mode 100644 index f3726178..00000000 --- a/mytoninstaller.py +++ /dev/null @@ -1,1051 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf_8 -*- - -import pwd -import random -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, 'THA' - ton-http-api. 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 == "THA": - CreateLocalConfigFile(args, localhost=True) - 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, localhost=False): - # 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() - if localhost is True: - liteServerConfig["ip"] = 2130706433 # 127.0.0.1 - localConfigPath = localConfigPath.replace("local", "localhost") - 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, localhost=False): - if localhost is True: - event_name = "clcl" - else: - event_name = "clc" - initBlock = GetInitBlock() - initBlock_b64 = dict2b64(initBlock) - args = ["python3", local.buffer.my_path, "-u", local.buffer.user, "-e", event_name, "-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 == "enableTHA": - EnableTonHttpApi() - if name in ["clc", "clcl"]: - ix = sys.argv.index("-i") - initBlock_b64 = sys.argv[ix+1] - initBlock = b642dict(initBlock_b64) - if name == "clcl": - CreateLocalConfig(initBlock, localhost=True) - else: - 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(): - local.add_log("start FirstNodeSettings fuction", "debug") - - # Создать переменные - user = local.buffer.user - vuser = local.buffer.vuser - ton_work_dir = local.buffer.ton_work_dir - ton_db_dir = local.buffer.ton_db_dir - keys_dir = local.buffer.keys_dir - tonLogPath = local.buffer.ton_log_path - validatorAppPath = local.buffer.validator_app_path - globalConfigPath = local.buffer.global_config_path - vconfig_path = local.buffer.vconfig_path - - # Проверить конфигурацию - if os.path.isfile(vconfig_path): - local.add_log("Validators config.json already exist. Break FirstNodeSettings fuction", "warning") - return - #end if - - # Создать пользователя - file = open("/etc/passwd", 'rt') - text = file.read() - file.close() - if vuser not in text: - local.add_log("Creating new user: " + vuser, "debug") - args = ["/usr/sbin/useradd", "-d", "/dev/null", "-s", "/dev/null", vuser] - subprocess.run(args) - #end if - - # Подготовить папки валидатора - os.makedirs(ton_db_dir, exist_ok=True) - os.makedirs(keys_dir, exist_ok=True) - - # Прописать автозагрузку - cpus = psutil.cpu_count() - 1 - cmd = "{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --verbosity 1" - cmd = cmd.format(validatorAppPath=validatorAppPath, globalConfigPath=globalConfigPath, ton_db_dir=ton_db_dir, tonLogPath=tonLogPath, cpus=cpus) - add2systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" - - # Получить внешний ip адрес - ip = get_own_ip() - vport = random.randint(2000, 65000) - addr = "{ip}:{vport}".format(ip=ip, vport=vport) - local.add_log("Use addr: " + addr, "debug") - - # Первый запуск - local.add_log("First start validator - create config.json", "debug") - args = [validatorAppPath, "--global-config", globalConfigPath, "--db", ton_db_dir, "--ip", addr, "--logname", tonLogPath] - subprocess.run(args) - - # Скачать дамп - DownloadDump() - - # chown 1 - local.add_log("Chown ton-work dir", "debug") - args = ["chown", "-R", vuser + ':' + vuser, ton_work_dir] - subprocess.run(args) - - # start validator - StartValidator() -#end define - -def DownloadDump(): - dump = local.buffer.dump - if dump == False: - return - #end if - - local.add_log("start DownloadDump fuction", "debug") - url = "https://dump.ton.org" - dumpSize = requests.get(url + "/dumps/latest.size.archive.txt").text - print("dumpSize:", dumpSize) - needSpace = int(dumpSize) * 3 - diskSpace = psutil.disk_usage("/var") - if needSpace > diskSpace.free: - return - #end if - - # apt install - cmd = "apt install plzip pv -y" - os.system(cmd) - - # download dump - cmd = "curl -s {url}/dumps/latest.tar.lz | pv | plzip -d -n8 | tar -xC /var/ton-work/db".format(url=url) - os.system(cmd) -#end define - -def FirstMytoncoreSettings(): - 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") - - # Проверить конфигурацию - path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) - 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") - return - #end if - - #amazon bugfix - path1 = "/home/{user}/.local/".format(user=user) - path2 = path1 + "share/" - chownOwner = "{user}:{user}".format(user=user) - os.makedirs(path1, exist_ok=True) - os.makedirs(path2, exist_ok=True) - args = ["chown", chownOwner, path1, path2] - subprocess.run(args) - - # Подготовить папку mytoncore - mconfig_path = local.buffer.mconfig_path - mconfigDir = get_dir_from_path(mconfig_path) - os.makedirs(mconfigDir, exist_ok=True) - - # create variables - src_dir = local.buffer.src_dir - ton_bin_dir = local.buffer.ton_bin_dir - ton_src_dir = local.buffer.ton_src_dir - - # general config - mconfig = Dict() - mconfig.config = Dict() - mconfig.config.logLevel = "debug" - mconfig.config.isLocaldbSaving = True - - # fift - fift = Dict() - fift.appPath = ton_bin_dir + "crypto/fift" - fift.libsPath = ton_src_dir + "crypto/fift/lib" - fift.smartcontsPath = ton_src_dir + "crypto/smartcont" - mconfig.fift = fift - - # lite-client - liteClient = Dict() - liteClient.appPath = ton_bin_dir + "lite-client/lite-client" - liteClient.configPath = ton_bin_dir + "global.config.json" - mconfig.liteClient = liteClient - - # Telemetry - mconfig.sendTelemetry = local.buffer.telemetry - - # Записать настройки в файл - SetConfig(path=mconfig_path, data=mconfig) - - # chown 1 - args = ["chown", user + ':' + user, mconfigDir, mconfig_path] - subprocess.run(args) - - # start mytoncore - StartMytoncore() -#end define - -def EnableValidatorConsole(): - local.add_log("start EnableValidatorConsole function", "debug") - - # Create variables - user = local.buffer.user - vuser = local.buffer.vuser - cport = local.buffer.cport - src_dir = local.buffer.src_dir - ton_db_dir = local.buffer.ton_db_dir - ton_bin_dir = local.buffer.ton_bin_dir - vconfig_path = local.buffer.vconfig_path - generate_random_id = ton_bin_dir + "utils/generate-random-id" - keys_dir = local.buffer.keys_dir - client_key = keys_dir + "client" - server_key = keys_dir + "server" - client_pubkey = client_key + ".pub" - 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") - return - #end if - - # generate server key - args = [generate_random_id, "--mode", "keys", "--name", server_key] - process = subprocess.run(args, stdout=subprocess.PIPE) - output = process.stdout.decode("utf-8") - output_arr = output.split(' ') - server_key_hex = output_arr[0] - server_key_b64 = output_arr[1].replace('\n', '') - - # move key - newKeyPath = ton_db_dir + "/keyring/" + server_key_hex - args = ["mv", server_key, newKeyPath] - subprocess.run(args) - - # generate client key - args = [generate_random_id, "--mode", "keys", "--name", client_key] - process = subprocess.run(args, stdout=subprocess.PIPE) - output = process.stdout.decode("utf-8") - output_arr = output.split(' ') - client_key_hex = output_arr[0] - client_key_b64 = output_arr[1].replace('\n', '') - - # chown 1 - args = ["chown", vuser + ':' + vuser, newKeyPath] - subprocess.run(args) - - # chown 2 - args = ["chown", user + ':' + user, server_pubkey, client_key, client_pubkey] - subprocess.run(args) - - # read vconfig - vconfig = GetConfig(path=vconfig_path) - - # prepare config - control = Dict() - control.id = server_key_b64 - control.port = cport - allowed = Dict() - allowed.id = client_key_b64 - allowed.permissions = 15 - control.allowed = [allowed] # fix me - vconfig.control.append(control) - - # write vconfig - SetConfig(path=vconfig_path, data=vconfig) - - # restart validator - StartValidator() - - # read mconfig - mconfig_path = local.buffer.mconfig_path - mconfig = GetConfig(path=mconfig_path) - - # edit mytoncore config file - validatorConsole = Dict() - validatorConsole.appPath = ton_bin_dir + "validator-engine-console/validator-engine-console" - validatorConsole.privKeyPath = client_key - validatorConsole.pubKeyPath = server_pubkey - validatorConsole.addr = "127.0.0.1:{cport}".format(cport=cport) - mconfig.validatorConsole = validatorConsole - - # write mconfig - SetConfig(path=mconfig_path, data=mconfig) - - # Подтянуть событие в mytoncore.py - cmd = "python3 {src_dir}mytonctrl/mytoncore.py -e \"enableVC\"".format(src_dir=src_dir) - args = ["su", "-l", user, "-c", cmd] - subprocess.run(args) - - # restart mytoncore - StartMytoncore() -#end define - -def EnableLiteServer(): - local.add_log("start EnableLiteServer function", "debug") - - # Create variables - user = local.buffer.user - vuser = local.buffer.vuser - lport = local.buffer.lport - src_dir = local.buffer.src_dir - ton_db_dir = local.buffer.ton_db_dir - keys_dir = local.buffer.keys_dir - ton_bin_dir = local.buffer.ton_bin_dir - vconfig_path = local.buffer.vconfig_path - generate_random_id = ton_bin_dir + "utils/generate-random-id" - liteserver_key = keys_dir + "liteserver" - liteserver_pubkey = liteserver_key + ".pub" - - # Check if key exist - if os.path.isfile(liteserver_pubkey): - local.add_log("Liteserver key already exist. Break EnableLiteServer fuction", "warning") - return - #end if - - # generate liteserver key - local.add_log("generate liteserver key", "debug") - args = [generate_random_id, "--mode", "keys", "--name", liteserver_key] - process = subprocess.run(args, stdout=subprocess.PIPE) - output = process.stdout.decode("utf-8") - output_arr = output.split(' ') - liteserver_key_hex = output_arr[0] - liteserver_key_b64 = output_arr[1].replace('\n', '') - - # move key - local.add_log("move key", "debug") - newKeyPath = ton_db_dir + "/keyring/" + liteserver_key_hex - args = ["mv", liteserver_key, newKeyPath] - subprocess.run(args) - - # chown 1 - local.add_log("chown 1", "debug") - args = ["chown", vuser + ':' + vuser, newKeyPath] - subprocess.run(args) - - # chown 2 - local.add_log("chown 2", "debug") - args = ["chown", user + ':' + user, liteserver_pubkey] - subprocess.run(args) - - # read vconfig - local.add_log("read vconfig", "debug") - vconfig = GetConfig(path=vconfig_path) - - # prepare vconfig - local.add_log("prepare vconfig", "debug") - liteserver = Dict() - liteserver.id = liteserver_key_b64 - liteserver.port = lport - vconfig.liteservers.append(liteserver) - - # write vconfig - local.add_log("write vconfig", "debug") - SetConfig(path=vconfig_path, data=vconfig) - - # restart validator - StartValidator() - - # edit mytoncore config file - # 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") - liteServer = Dict() - liteServer.pubkeyPath = liteserver_pubkey - liteServer.ip = "127.0.0.1" - liteServer.port = lport - mconfig.liteClient.liteServer = liteServer - - # write mconfig - local.add_log("write mconfig", "debug") - SetConfig(path=mconfig_path, data=mconfig) - - # restart mytoncore - StartMytoncore() -#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 StartMytoncore(): - # restart mytoncore - local.add_log("Start/restart mytoncore service", "debug") - args = ["systemctl", "restart", "mytoncore"] - subprocess.run(args) -#end define - -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.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.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(): - 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() -#end define - -def DangerousRecoveryValidatorConfigFile(): - local.add_log("start DangerousRecoveryValidatorConfigFile function", "info") - - # install and import cryptography library - args = ["pip3", "install", "cryptography"] - subprocess.run(args) - from cryptography.hazmat.primitives import serialization - from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - - # Get keys from keyring - keys = list() - keyringDir = "/var/ton-work/db/keyring/" - keyring = os.listdir(keyringDir) - os.chdir(keyringDir) - sorted(keyring, key=os.path.getmtime) - for item in keyring: - b64String = hex2b64(item) - keys.append(b64String) - #end for - - # Create config object - vconfig = Dict() - vconfig["@type"] = "engine.validator.config" - vconfig.out_port = 3278 - - # Create addrs object - buff = Dict() - buff["@type"] = "engine.addr" - buff.ip = ip2int(get_own_ip()) - buff.port = None - buff.categories = [0, 1, 2, 3] - buff.priority_categories = [] - vconfig.addrs = [buff] - - # Get liteserver fragment - mconfig_path = local.buffer.mconfig_path - mconfig = GetConfig(path=mconfig_path) - lkey = mconfig.liteClient.liteServer.pubkeyPath - lport = mconfig.liteClient.liteServer.port - - # Read lite server pubkey - file = open(lkey, 'rb') - data = file.read() - file.close() - ls_pubkey = data[4:] - - # Search lite server priv key - for item in keyring: - path = keyringDir + item - file = open(path, 'rb') - data = file.read() - file.close() - peivkey = data[4:] - privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) - pubkeyObject = privkeyObject.public_key() - pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) - if pubkey == ls_pubkey: - ls_id = hex2b64(item) - keys.remove(ls_id) - #end for - - # Create LS object - buff = Dict() - buff["@type"] = "engine.liteServer" - buff.id = ls_id - buff.port = lport - vconfig.liteservers = [buff] - - # Get validator-console fragment - ckey = mconfig.validatorConsole.pubKeyPath - addr = mconfig.validatorConsole.addr - buff = addr.split(':') - cport = int(buff[1]) - - # Read validator-console pubkey - file = open(ckey, 'rb') - data = file.read() - file.close() - vPubkey = data[4:] - - # Search validator-console priv key - for item in keyring: - path = keyringDir + item - file = open(path, 'rb') - data = file.read() - file.close() - peivkey = data[4:] - privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) - pubkeyObject = privkeyObject.public_key() - pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) - if pubkey == vPubkey: - vcId = hex2b64(item) - keys.remove(vcId) - #end for - - # Create VC object - buff = Dict() - buff2 = Dict() - buff["@type"] = "engine.controlInterface" - buff.id = vcId - buff.port = cport - buff2["@type"] = "engine.controlProcess" - buff2.id = None - buff2.permissions = 15 - buff.allowed = buff2 - vconfig.control = [buff] - - # Get dht fragment - files = os.listdir("/var/ton-work/db") - for item in files: - if item[:3] == "dht": - dhtS = item[4:] - dhtS = dhtS.replace('_', '/') - dhtS = dhtS.replace('-', '+') - break - #end for - - # Get ght from keys - for item in keys: - if dhtS in item: - dhtId = item - keys.remove(dhtId) - #end for - - # Create dht object - buff = Dict() - buff["@type"] = "engine.dht" - buff.id = dhtId - vconfig.dht = [buff] - - # Create adnl object - adnl2 = Dict() - adnl2["@type"] = "engine.adnl" - adnl2.id = dhtId - adnl2.category = 0 - - # Create adnl object - adnlId = hex2b64(mconfig["adnlAddr"]) - keys.remove(adnlId) - adnl3 = Dict() - adnl3["@type"] = "engine.adnl" - adnl3.id = adnlId - adnl3.category = 0 - - # Create adnl object - adnl1 = Dict() - adnl1["@type"] = "engine.adnl" - adnl1.id = keys.pop(0) - adnl1.category = 1 - - vconfig.adnl = [adnl1, adnl2, adnl3] - - # Get dumps from tmp - dumps = list() - dumpsDir = "/tmp/mytoncore/" - dumpsList = os.listdir(dumpsDir) - os.chdir(dumpsDir) - sorted(dumpsList, key=os.path.getmtime) - for item in dumpsList: - if "ElectionEntry.json" in item: - dumps.append(item) - #end for - - # Create validators object - validators = list() - - # Read dump file - while len(keys) > 0: - dumpPath = dumps.pop() - file = open(dumpPath, 'rt') - data = file.read() - file.close() - dump = json.loads(data) - vkey = hex2b64(dump["validatorKey"]) - temp_key = Dict() - temp_key["@type"] = "engine.validatorTempKey" - temp_key.key = vkey - temp_key.expire_at = dump["endWorkTime"] - adnl_addr = Dict() - adnl_addr["@type"] = "engine.validatorAdnlAddress" - adnl_addr.id = adnlId - adnl_addr.expire_at = dump["endWorkTime"] - - # Create validator object - validator = Dict() - validator["@type"] = "engine.validator" - validator.id = vkey - validator.temp_keys = [temp_key] - validator.adnl_addrs = [adnl_addr] - validator.election_date = dump["startWorkTime"] - validator.expire_at = dump["endWorkTime"] - if vkey in keys: - validators.append(validator) - keys.remove(vkey) - #end if - #end while - - # Add validators object to vconfig - vconfig.validators = validators - - - print("vconfig:", json.dumps(vconfig, indent=4)) - 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(): - local.add_log("start CreateSymlinks fuction", "debug") - cport = local.buffer.cport - - mytonctrl_file = "/usr/bin/mytonctrl" - fift_file = "/usr/bin/fift" - liteclient_file = "/usr/bin/lite-client" - 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.close() - file = open(fift_file, 'wt') - file.write("/usr/bin/ton/crypto/fift $@") - file.close() - file = open(liteclient_file, 'wt') - file.write("/usr/bin/ton/lite-client/lite-client -C /usr/bin/ton/global.config.json $@") - file.close() - if cport: - file = open(validator_console_file, 'wt') - file.write("/usr/bin/ton/validator-engine-console/validator-engine-console -k /var/ton-work/keys/client -p /var/ton-work/keys/server.pub -a 127.0.0.1:" + str(cport) + " $@") - file.close() - args = ["chmod", "+x", validator_console_file] - subprocess.run(args) - args = ["chmod", "+x", mytonctrl_file, fift_file, liteclient_file] - subprocess.run(args) - - # env - fiftpath = "export FIFTPATH=/usr/src/ton/crypto/fift/lib/:/usr/src/ton/crypto/smartcont/" - file = open(env_file, 'rt+') - text = file.read() - if fiftpath not in text: - 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 EnableTonHttpApi(): - local.add_log("start EnableTonHttpApi function", "debug") - exitCode = run_as_root(["bash", "/usr/src/mytonctrl/scripts/ton_http_api_installer.sh", "-u", local.buffer.user]) - if exitCode == 0: - text = "EnableTonHttpApi - {green}OK{endc}" - else: - text = "EnableTonHttpApi - {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 From 0dc1f6d8a7f8312c87dab1020fdc4350ad17161b Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 1 Mar 2024 17:08:56 +0700 Subject: [PATCH 121/236] rm mytoncinstaller --- mytoninstaller.py | 1042 --------------------------------------------- 1 file changed, 1042 deletions(-) delete mode 100644 mytoninstaller.py diff --git a/mytoninstaller.py b/mytoninstaller.py deleted file mode 100644 index b14fb194..00000000 --- a/mytoninstaller.py +++ /dev/null @@ -1,1042 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf_8 -*- - -import pwd -import random -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(): - local.add_log("start FirstNodeSettings fuction", "debug") - - # Создать переменные - user = local.buffer.user - vuser = local.buffer.vuser - ton_work_dir = local.buffer.ton_work_dir - ton_db_dir = local.buffer.ton_db_dir - keys_dir = local.buffer.keys_dir - tonLogPath = local.buffer.ton_log_path - validatorAppPath = local.buffer.validator_app_path - globalConfigPath = local.buffer.global_config_path - vconfig_path = local.buffer.vconfig_path - - # Проверить конфигурацию - if os.path.isfile(vconfig_path): - local.add_log("Validators config.json already exist. Break FirstNodeSettings fuction", "warning") - return - #end if - - # Создать пользователя - file = open("/etc/passwd", 'rt') - text = file.read() - file.close() - if vuser not in text: - local.add_log("Creating new user: " + vuser, "debug") - args = ["/usr/sbin/useradd", "-d", "/dev/null", "-s", "/dev/null", vuser] - subprocess.run(args) - #end if - - # Подготовить папки валидатора - os.makedirs(ton_db_dir, exist_ok=True) - os.makedirs(keys_dir, exist_ok=True) - - # Прописать автозагрузку - cpus = psutil.cpu_count() - 1 - cmd = "{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --verbosity 1" - cmd = cmd.format(validatorAppPath=validatorAppPath, globalConfigPath=globalConfigPath, ton_db_dir=ton_db_dir, tonLogPath=tonLogPath, cpus=cpus) - add2systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" - - # Получить внешний ip адрес - ip = get_own_ip() - vport = random.randint(2000, 65000) - addr = "{ip}:{vport}".format(ip=ip, vport=vport) - local.add_log("Use addr: " + addr, "debug") - - # Первый запуск - local.add_log("First start validator - create config.json", "debug") - args = [validatorAppPath, "--global-config", globalConfigPath, "--db", ton_db_dir, "--ip", addr, "--logname", tonLogPath] - subprocess.run(args) - - # Скачать дамп - DownloadDump() - - # chown 1 - local.add_log("Chown ton-work dir", "debug") - args = ["chown", "-R", vuser + ':' + vuser, ton_work_dir] - subprocess.run(args) - - # start validator - StartValidator() -#end define - -def DownloadDump(): - dump = local.buffer.dump - if dump == False: - return - #end if - - local.add_log("start DownloadDump fuction", "debug") - url = "https://dump.ton.org" - dumpSize = requests.get(url + "/dumps/latest.size.archive.txt").text - print("dumpSize:", dumpSize) - needSpace = int(dumpSize) * 3 - diskSpace = psutil.disk_usage("/var") - if needSpace > diskSpace.free: - return - #end if - - # apt install - cmd = "apt install plzip pv -y" - os.system(cmd) - - # download dump - cmd = "curl -Ls {url}/dumps/latest.tar.lz | pv | plzip -d -n8 | tar -xC /var/ton-work/db".format(url=url) - os.system(cmd) -#end define - -def FirstMytoncoreSettings(): - 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") - - # Проверить конфигурацию - path = "/home/{user}/.local/share/mytoncore/mytoncore.db".format(user=user) - 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") - return - #end if - - #amazon bugfix - path1 = "/home/{user}/.local/".format(user=user) - path2 = path1 + "share/" - chownOwner = "{user}:{user}".format(user=user) - os.makedirs(path1, exist_ok=True) - os.makedirs(path2, exist_ok=True) - args = ["chown", chownOwner, path1, path2] - subprocess.run(args) - - # Подготовить папку mytoncore - mconfig_path = local.buffer.mconfig_path - mconfigDir = get_dir_from_path(mconfig_path) - os.makedirs(mconfigDir, exist_ok=True) - - # create variables - src_dir = local.buffer.src_dir - ton_bin_dir = local.buffer.ton_bin_dir - ton_src_dir = local.buffer.ton_src_dir - - # general config - mconfig = Dict() - mconfig.config = Dict() - mconfig.config.logLevel = "debug" - mconfig.config.isLocaldbSaving = True - - # fift - fift = Dict() - fift.appPath = ton_bin_dir + "crypto/fift" - fift.libsPath = ton_src_dir + "crypto/fift/lib" - fift.smartcontsPath = ton_src_dir + "crypto/smartcont" - mconfig.fift = fift - - # lite-client - liteClient = Dict() - liteClient.appPath = ton_bin_dir + "lite-client/lite-client" - liteClient.configPath = ton_bin_dir + "global.config.json" - mconfig.liteClient = liteClient - - # Telemetry - mconfig.sendTelemetry = local.buffer.telemetry - - # Записать настройки в файл - SetConfig(path=mconfig_path, data=mconfig) - - # chown 1 - args = ["chown", user + ':' + user, mconfigDir, mconfig_path] - subprocess.run(args) - - # start mytoncore - StartMytoncore() -#end define - -def EnableValidatorConsole(): - local.add_log("start EnableValidatorConsole function", "debug") - - # Create variables - user = local.buffer.user - vuser = local.buffer.vuser - cport = local.buffer.cport - src_dir = local.buffer.src_dir - ton_db_dir = local.buffer.ton_db_dir - ton_bin_dir = local.buffer.ton_bin_dir - vconfig_path = local.buffer.vconfig_path - generate_random_id = ton_bin_dir + "utils/generate-random-id" - keys_dir = local.buffer.keys_dir - client_key = keys_dir + "client" - server_key = keys_dir + "server" - client_pubkey = client_key + ".pub" - 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") - return - #end if - - # generate server key - args = [generate_random_id, "--mode", "keys", "--name", server_key] - process = subprocess.run(args, stdout=subprocess.PIPE) - output = process.stdout.decode("utf-8") - output_arr = output.split(' ') - server_key_hex = output_arr[0] - server_key_b64 = output_arr[1].replace('\n', '') - - # move key - newKeyPath = ton_db_dir + "/keyring/" + server_key_hex - args = ["mv", server_key, newKeyPath] - subprocess.run(args) - - # generate client key - args = [generate_random_id, "--mode", "keys", "--name", client_key] - process = subprocess.run(args, stdout=subprocess.PIPE) - output = process.stdout.decode("utf-8") - output_arr = output.split(' ') - client_key_hex = output_arr[0] - client_key_b64 = output_arr[1].replace('\n', '') - - # chown 1 - args = ["chown", vuser + ':' + vuser, newKeyPath] - subprocess.run(args) - - # chown 2 - args = ["chown", user + ':' + user, server_pubkey, client_key, client_pubkey] - subprocess.run(args) - - # read vconfig - vconfig = GetConfig(path=vconfig_path) - - # prepare config - control = Dict() - control.id = server_key_b64 - control.port = cport - allowed = Dict() - allowed.id = client_key_b64 - allowed.permissions = 15 - control.allowed = [allowed] # fix me - vconfig.control.append(control) - - # write vconfig - SetConfig(path=vconfig_path, data=vconfig) - - # restart validator - StartValidator() - - # read mconfig - mconfig_path = local.buffer.mconfig_path - mconfig = GetConfig(path=mconfig_path) - - # edit mytoncore config file - validatorConsole = Dict() - validatorConsole.appPath = ton_bin_dir + "validator-engine-console/validator-engine-console" - validatorConsole.privKeyPath = client_key - validatorConsole.pubKeyPath = server_pubkey - validatorConsole.addr = "127.0.0.1:{cport}".format(cport=cport) - mconfig.validatorConsole = validatorConsole - - # write mconfig - SetConfig(path=mconfig_path, data=mconfig) - - # Подтянуть событие в mytoncore.py - cmd = "python3 {src_dir}mytonctrl/mytoncore.py -e \"enableVC\"".format(src_dir=src_dir) - args = ["su", "-l", user, "-c", cmd] - subprocess.run(args) - - # restart mytoncore - StartMytoncore() -#end define - -def EnableLiteServer(): - local.add_log("start EnableLiteServer function", "debug") - - # Create variables - user = local.buffer.user - vuser = local.buffer.vuser - lport = local.buffer.lport - src_dir = local.buffer.src_dir - ton_db_dir = local.buffer.ton_db_dir - keys_dir = local.buffer.keys_dir - ton_bin_dir = local.buffer.ton_bin_dir - vconfig_path = local.buffer.vconfig_path - generate_random_id = ton_bin_dir + "utils/generate-random-id" - liteserver_key = keys_dir + "liteserver" - liteserver_pubkey = liteserver_key + ".pub" - - # Check if key exist - if os.path.isfile(liteserver_pubkey): - local.add_log("Liteserver key already exist. Break EnableLiteServer fuction", "warning") - return - #end if - - # generate liteserver key - local.add_log("generate liteserver key", "debug") - args = [generate_random_id, "--mode", "keys", "--name", liteserver_key] - process = subprocess.run(args, stdout=subprocess.PIPE) - output = process.stdout.decode("utf-8") - output_arr = output.split(' ') - liteserver_key_hex = output_arr[0] - liteserver_key_b64 = output_arr[1].replace('\n', '') - - # move key - local.add_log("move key", "debug") - newKeyPath = ton_db_dir + "/keyring/" + liteserver_key_hex - args = ["mv", liteserver_key, newKeyPath] - subprocess.run(args) - - # chown 1 - local.add_log("chown 1", "debug") - args = ["chown", vuser + ':' + vuser, newKeyPath] - subprocess.run(args) - - # chown 2 - local.add_log("chown 2", "debug") - args = ["chown", user + ':' + user, liteserver_pubkey] - subprocess.run(args) - - # read vconfig - local.add_log("read vconfig", "debug") - vconfig = GetConfig(path=vconfig_path) - - # prepare vconfig - local.add_log("prepare vconfig", "debug") - liteserver = Dict() - liteserver.id = liteserver_key_b64 - liteserver.port = lport - vconfig.liteservers.append(liteserver) - - # write vconfig - local.add_log("write vconfig", "debug") - SetConfig(path=vconfig_path, data=vconfig) - - # restart validator - StartValidator() - - # edit mytoncore config file - # 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") - liteServer = Dict() - liteServer.pubkeyPath = liteserver_pubkey - liteServer.ip = "127.0.0.1" - liteServer.port = lport - mconfig.liteClient.liteServer = liteServer - - # write mconfig - local.add_log("write mconfig", "debug") - SetConfig(path=mconfig_path, data=mconfig) - - # restart mytoncore - StartMytoncore() -#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 StartMytoncore(): - # restart mytoncore - local.add_log("Start/restart mytoncore service", "debug") - args = ["systemctl", "restart", "mytoncore"] - subprocess.run(args) -#end define - -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.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.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(): - 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() -#end define - -def DangerousRecoveryValidatorConfigFile(): - local.add_log("start DangerousRecoveryValidatorConfigFile function", "info") - - # install and import cryptography library - args = ["pip3", "install", "cryptography"] - subprocess.run(args) - from cryptography.hazmat.primitives import serialization - from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey - - # Get keys from keyring - keys = list() - keyringDir = "/var/ton-work/db/keyring/" - keyring = os.listdir(keyringDir) - os.chdir(keyringDir) - sorted(keyring, key=os.path.getmtime) - for item in keyring: - b64String = hex2b64(item) - keys.append(b64String) - #end for - - # Create config object - vconfig = Dict() - vconfig["@type"] = "engine.validator.config" - vconfig.out_port = 3278 - - # Create addrs object - buff = Dict() - buff["@type"] = "engine.addr" - buff.ip = ip2int(get_own_ip()) - buff.port = None - buff.categories = [0, 1, 2, 3] - buff.priority_categories = [] - vconfig.addrs = [buff] - - # Get liteserver fragment - mconfig_path = local.buffer.mconfig_path - mconfig = GetConfig(path=mconfig_path) - lkey = mconfig.liteClient.liteServer.pubkeyPath - lport = mconfig.liteClient.liteServer.port - - # Read lite server pubkey - file = open(lkey, 'rb') - data = file.read() - file.close() - ls_pubkey = data[4:] - - # Search lite server priv key - for item in keyring: - path = keyringDir + item - file = open(path, 'rb') - data = file.read() - file.close() - peivkey = data[4:] - privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) - pubkeyObject = privkeyObject.public_key() - pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) - if pubkey == ls_pubkey: - ls_id = hex2b64(item) - keys.remove(ls_id) - #end for - - # Create LS object - buff = Dict() - buff["@type"] = "engine.liteServer" - buff.id = ls_id - buff.port = lport - vconfig.liteservers = [buff] - - # Get validator-console fragment - ckey = mconfig.validatorConsole.pubKeyPath - addr = mconfig.validatorConsole.addr - buff = addr.split(':') - cport = int(buff[1]) - - # Read validator-console pubkey - file = open(ckey, 'rb') - data = file.read() - file.close() - vPubkey = data[4:] - - # Search validator-console priv key - for item in keyring: - path = keyringDir + item - file = open(path, 'rb') - data = file.read() - file.close() - peivkey = data[4:] - privkeyObject = Ed25519PrivateKey.from_private_bytes(peivkey) - pubkeyObject = privkeyObject.public_key() - pubkey = pubkeyObject.public_bytes(encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw) - if pubkey == vPubkey: - vcId = hex2b64(item) - keys.remove(vcId) - #end for - - # Create VC object - buff = Dict() - buff2 = Dict() - buff["@type"] = "engine.controlInterface" - buff.id = vcId - buff.port = cport - buff2["@type"] = "engine.controlProcess" - buff2.id = None - buff2.permissions = 15 - buff.allowed = buff2 - vconfig.control = [buff] - - # Get dht fragment - files = os.listdir("/var/ton-work/db") - for item in files: - if item[:3] == "dht": - dhtS = item[4:] - dhtS = dhtS.replace('_', '/') - dhtS = dhtS.replace('-', '+') - break - #end for - - # Get ght from keys - for item in keys: - if dhtS in item: - dhtId = item - keys.remove(dhtId) - #end for - - # Create dht object - buff = Dict() - buff["@type"] = "engine.dht" - buff.id = dhtId - vconfig.dht = [buff] - - # Create adnl object - adnl2 = Dict() - adnl2["@type"] = "engine.adnl" - adnl2.id = dhtId - adnl2.category = 0 - - # Create adnl object - adnlId = hex2b64(mconfig["adnlAddr"]) - keys.remove(adnlId) - adnl3 = Dict() - adnl3["@type"] = "engine.adnl" - adnl3.id = adnlId - adnl3.category = 0 - - # Create adnl object - adnl1 = Dict() - adnl1["@type"] = "engine.adnl" - adnl1.id = keys.pop(0) - adnl1.category = 1 - - vconfig.adnl = [adnl1, adnl2, adnl3] - - # Get dumps from tmp - dumps = list() - dumpsDir = "/tmp/mytoncore/" - dumpsList = os.listdir(dumpsDir) - os.chdir(dumpsDir) - sorted(dumpsList, key=os.path.getmtime) - for item in dumpsList: - if "ElectionEntry.json" in item: - dumps.append(item) - #end for - - # Create validators object - validators = list() - - # Read dump file - while len(keys) > 0: - dumpPath = dumps.pop() - file = open(dumpPath, 'rt') - data = file.read() - file.close() - dump = json.loads(data) - vkey = hex2b64(dump["validatorKey"]) - temp_key = Dict() - temp_key["@type"] = "engine.validatorTempKey" - temp_key.key = vkey - temp_key.expire_at = dump["endWorkTime"] - adnl_addr = Dict() - adnl_addr["@type"] = "engine.validatorAdnlAddress" - adnl_addr.id = adnlId - adnl_addr.expire_at = dump["endWorkTime"] - - # Create validator object - validator = Dict() - validator["@type"] = "engine.validator" - validator.id = vkey - validator.temp_keys = [temp_key] - validator.adnl_addrs = [adnl_addr] - validator.election_date = dump["startWorkTime"] - validator.expire_at = dump["endWorkTime"] - if vkey in keys: - validators.append(validator) - keys.remove(vkey) - #end if - #end while - - # Add validators object to vconfig - vconfig.validators = validators - - - print("vconfig:", json.dumps(vconfig, indent=4)) - 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(): - local.add_log("start CreateSymlinks fuction", "debug") - cport = local.buffer.cport - - mytonctrl_file = "/usr/bin/mytonctrl" - fift_file = "/usr/bin/fift" - liteclient_file = "/usr/bin/lite-client" - 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.close() - file = open(fift_file, 'wt') - file.write("/usr/bin/ton/crypto/fift $@") - file.close() - file = open(liteclient_file, 'wt') - file.write("/usr/bin/ton/lite-client/lite-client -C /usr/bin/ton/global.config.json $@") - file.close() - if cport: - file = open(validator_console_file, 'wt') - file.write("/usr/bin/ton/validator-engine-console/validator-engine-console -k /var/ton-work/keys/client -p /var/ton-work/keys/server.pub -a 127.0.0.1:" + str(cport) + " $@") - file.close() - args = ["chmod", "+x", validator_console_file] - subprocess.run(args) - args = ["chmod", "+x", mytonctrl_file, fift_file, liteclient_file] - subprocess.run(args) - - # env - fiftpath = "export FIFTPATH=/usr/src/ton/crypto/fift/lib/:/usr/src/ton/crypto/smartcont/" - file = open(env_file, 'rt+') - text = file.read() - if fiftpath not in text: - 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 From 08e41d742f1e11a011a729be0853d46c1c2445ad Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 4 Mar 2024 13:03:27 +0700 Subject: [PATCH 122/236] add modes modules structure, add Controller mode --- mytoncore/modes.py | 4 + mytoncore/mytoncore.py | 30 ++++++ mytonctrl/modules/__init__.py | 0 mytonctrl/modules/controller.py | 150 ++++++++++++++++++++++++++ mytonctrl/modules/module.py | 12 +++ mytonctrl/mytonctrl.py | 185 +++++--------------------------- mytonctrl/utils.py | 5 + 7 files changed, 227 insertions(+), 159 deletions(-) create mode 100644 mytoncore/modes.py create mode 100644 mytonctrl/modules/__init__.py create mode 100644 mytonctrl/modules/controller.py create mode 100644 mytonctrl/modules/module.py create mode 100644 mytonctrl/utils.py diff --git a/mytoncore/modes.py b/mytoncore/modes.py new file mode 100644 index 00000000..62a64a67 --- /dev/null +++ b/mytoncore/modes.py @@ -0,0 +1,4 @@ +MODES = { # mode_name : is_enabled_by_default + 'Controller': False, + 'Validator': True +} \ No newline at end of file diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 8b79278a..c02f19f9 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -11,6 +11,7 @@ import requests from fastcrc import crc16 +from mytoncore.modes import MODES from mytoncore.utils import xhex2hex, ng2g from mytoncore.liteclient import LiteClient from mytoncore.validator_console import ValidatorConsole @@ -3207,6 +3208,35 @@ def SetSettings(self, name, data): self.local.save() #end define + def get_modes(self): + current_modes = self.local.db.get('modes', {}) + if 'modes' not in self.local.db: + self.local.db['modes'] = current_modes + for mode in MODES: + if mode not in current_modes: + current_modes[mode] = MODES[mode] # assign default mode value + return current_modes + + def enable_mode(self, name): + if name not in MODES: + raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') + current_modes = self.get_modes() + current_modes[name] = True + self.local.save() + + def disable_mode(self, name): + if name not in MODES: + raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') + current_modes = self.get_modes() + current_modes[name] = False + self.local.save() + + def get_mode_value(self, name): + current_modes = self.get_modes() + if name not in current_modes: + raise Exception(f'No mode named {name} found in current modes: {current_modes}') + return current_modes[name] + def Tlb2Json(self, text): # Заменить скобки start = 0 diff --git a/mytonctrl/modules/__init__.py b/mytonctrl/modules/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/mytonctrl/modules/controller.py b/mytonctrl/modules/controller.py new file mode 100644 index 00000000..8875d33d --- /dev/null +++ b/mytonctrl/modules/controller.py @@ -0,0 +1,150 @@ +import json +from mypylib.mypylib import color_print, print_table + +from ..utils import GetItemFromList +from .module import MtcModule + + +class ControllerModule(MtcModule): + + def create_controllers(self, args): + self.ton.CreateControllers() + color_print("CreateControllers - {green}OK{endc}") + + def print_controllers_list(self, args): + new_controllers = self.ton.GetControllers() + using_controllers = self.ton.GetSettings("using_controllers") + old_controllers = self.ton.GetSettings("old_controllers") + user_controllers_list = self.ton.GetSettings("user_controllers_list") + print("using controllers:") + self.print_controllers_list_process(using_controllers) + if new_controllers != using_controllers: + print() + print("new controllers:") + self.print_controllers_list_process(new_controllers) + if old_controllers is not None and len(old_controllers) > 0: + print() + print("old controllers:") + self.print_controllers_list_process(old_controllers) + if user_controllers_list is not None and len(user_controllers_list) > 0: + print() + print("user controllers:") + self.print_controllers_list_process(user_controllers_list) + + def print_controllers_list_process(self, controllers): + table = list() + table += [["Address", "Status", "Balance", "Approved", "State"]] + for controllerAddr in controllers: + account = self.ton.GetAccount(controllerAddr) + controllerData = self.ton.GetControllerData(controllerAddr) + approved = True if controllerData and controllerData["approved"] == -1 else False + state = controllerData["state"] if controllerData else None + table += [[controllerAddr, account.status, account.balance, approved, state]] + print_table(table) + + def get_controller_data(self, args): + try: + controller_addr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} get_controller_data ") + return + controller_data = self.ton.GetControllerData(controller_addr) + print(json.dumps(controller_data, indent=4)) + + def deposit_to_controller(self, args): + try: + controller_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} deposit_to_controller ") + return + self.ton.DepositToController(controller_addr, amount) + + def withdraw_from_controller(self, args): + try: + controller_addr = args[0] + amount = GetItemFromList(args, 1) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") + return + self.ton.WithdrawFromController(controller_addr, amount) + + def calculate_annual_controller_percentage(self, args): + try: + percent_per_round = float(args[0]) + except: + percent_per_round = self.ton.GetSettings("max_interest_percent") + config15 = self.ton.GetConfig(15) + roundPeriod = config15["validators_elected_for"] + rounds = 365 * 24 * 3600 / roundPeriod + yearInterest = (1 + percent_per_round / 100) * rounds + yearInterestPercent = round(yearInterest / 100, 2) + print("roundPeriod", roundPeriod) + print("rounds", rounds) + print("percentPerRound", percent_per_round) + print("yearInterest", yearInterest) + print(f"yearInterestPercent: {yearInterestPercent}%") + + def controller_update_validator_set(self, args): + try: + controller_addr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} controller_update_validator_set ") + return + self.ton.ControllerUpdateValidatorSet(controller_addr) + color_print("ControllerUpdateValidatorSet - {green}OK{endc}") + + def stop_controller(self, args): + try: + controller_addr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} stop_controller ") + return + self.ton.StopController(controller_addr) + color_print("StopController - {green}OK{endc}") + + def stop_and_withdraw_controller(self, args): + try: + controller_addr = args[0] + amount = GetItemFromList(args, 1) + except: + color_print("{red}Bad args. Usage:{endc} stop_and_withdraw_controller [amount]") + return + if amount is None: + account = self.ton.GetAccount(controller_addr) + amount = account.balance - 10.1 + self.ton.StopController(controller_addr) + self.ton.WithdrawFromController(controller_addr, amount) + color_print("StopAndWithdrawController - {green}OK{endc}") + + def add_controller(self, args): + try: + controller_addr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} add_controller ") + return + self.ton.AddController(controller_addr) + color_print("AddController - {green}OK{endc}") + + def check_liquid_pool(self, args): + self.ton.CheckLiquidPool() + color_print("CheckLiquidPool - {green}OK{endc}") + + def calculate_loan_amount_test(self, args): + t = self.ton.CalculateLoanAmount_test() + print(t) + + def add_console_commands(self, console): + console.AddItem("create_controllers", self.create_controllers, self.local.translate("_")) + console.AddItem("update_controllers", self.create_controllers, self.local.translate("_")) + console.AddItem("controllers_list", self.print_controllers_list, self.local.translate("_")) + console.AddItem("get_controller_data", self.get_controller_data, self.local.translate("_")) + console.AddItem("deposit_to_controller", self.deposit_to_controller, self.local.translate("_")) + console.AddItem("withdraw_from_controller", self.withdraw_from_controller, self.local.translate("_")) + console.AddItem("calculate_annual_controller_percentage", self.calculate_annual_controller_percentage, self.local.translate("_")) + console.AddItem("controller_update_validator_set", self.controller_update_validator_set, self.local.translate("_")) + console.AddItem("stop_controller", self.stop_controller, self.local.translate("_")) + console.AddItem("stop_and_withdraw_controller", self.stop_and_withdraw_controller, self.local.translate("_")) + console.AddItem("add_controller", self.add_controller, self.local.translate("_")) + console.AddItem("check_liquid_pool", self.check_liquid_pool, self.local.translate("_")) + console.AddItem("test_calculate_loan_amount", self.calculate_loan_amount_test, self.local.translate("_")) diff --git a/mytonctrl/modules/module.py b/mytonctrl/modules/module.py new file mode 100644 index 00000000..6ace8e49 --- /dev/null +++ b/mytonctrl/modules/module.py @@ -0,0 +1,12 @@ +from abc import ABC, abstractmethod +from mytoncore.mytoncore import MyTonCore + + +class MtcModule(ABC): + + def __init__(self, ton, local, *args, **kwargs): + self.ton: MyTonCore = ton + self.local = local + + @abstractmethod + def add_console_commands(self, console): ... diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 2b47e6a6..4401e0a7 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -42,6 +42,7 @@ GetBinGitHash, ) from mytonctrl.migrate import run_migrations +from .utils import GetItemFromList import sys, getopt, os @@ -138,19 +139,10 @@ def inject_globals(func): console.AddItem("activate_single_pool", inject_globals(activate_single_pool), local.translate("activate_single_pool_cmd")) console.AddItem("import_pool", inject_globals(import_pool), local.translate("import_pool_cmd")) - console.AddItem("create_controllers", inject_globals(CreateControllers), local.translate("_")) - console.AddItem("update_controllers", inject_globals(CreateControllers), local.translate("_")) - console.AddItem("controllers_list", inject_globals(PrintControllersList), local.translate("_")) - console.AddItem("get_controller_data", inject_globals(GetControllerData), local.translate("_")) - console.AddItem("deposit_to_controller", inject_globals(DepositToController), local.translate("_")) - console.AddItem("withdraw_from_controller", inject_globals(WithdrawFromController), local.translate("_")) - console.AddItem("calculate_annual_controller_percentage", inject_globals(CalculateAnnualControllerPercentage), local.translate("_")) - console.AddItem("controller_update_validator_set", inject_globals(ControllerUpdateValidatorSet), local.translate("_")) - console.AddItem("stop_controller", inject_globals(StopController), local.translate("_")) - console.AddItem("stop_and_withdraw_controller", inject_globals(StopAndWithdrawController), local.translate("_")) - console.AddItem("add_controller", inject_globals(AddController), local.translate("_")) - console.AddItem("check_liquid_pool", inject_globals(CheckLiquidPool), local.translate("_")) - console.AddItem("test_calculate_loan_amount", inject_globals(CalculateLoanAmount_test), local.translate("_")) + if ton.get_mode_value('Controller'): + from mytonctrl.modules.controller import ControllerModule + module = ControllerModule(ton, local) + module.add_console_commands(console) # console.AddItem("pt", inject_globals(PrintTest), "PrintTest") # console.AddItem("sl", inject_globals(sl), "sl") @@ -199,12 +191,6 @@ def Installer(args): subprocess.run(args) #end define -def GetItemFromList(data, index): - try: - return data[index] - except: pass -#end define - def GetAuthorRepoBranchFromArgs(args): data = dict() arg1 = GetItemFromList(args, 0) @@ -1250,6 +1236,27 @@ def SetSettings(ton, args): color_print("SetSettings - {green}OK{endc}") #end define + +def enable_mode(ton, args): + try: + name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} enable_mode ") + return + ton.enable_mode(name) + color_print("enable_mode - {green}OK{endc}") + + +def disable_mode(ton, args): + try: + name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} disable_mode ") + return + ton.disable_mode(name) + color_print("disable_mode - {green}OK{endc}") + + def Xrestart(inputArgs): if len(inputArgs) < 2: color_print("{red}Bad args. Usage:{endc} xrestart ") @@ -1503,146 +1510,6 @@ def import_pool(ton, args): color_print("import_pool - {green}OK{endc}") #end define -def CreateControllers(ton, args): - ton.CreateControllers() - color_print("CreateControllers - {green}OK{endc}") -#end define - -def PrintControllersList(ton, args): - new_controllers = ton.GetControllers() - using_controllers = ton.GetSettings("using_controllers") - old_controllers = ton.GetSettings("old_controllers") - user_controllers_list = ton.GetSettings("user_controllers_list") - print("using controllers:") - PrintControllersListProcess(ton, using_controllers) - if new_controllers != using_controllers: - print() - print("new controllers:") - PrintControllersListProcess(ton, new_controllers) - if old_controllers is not None and len(old_controllers) > 0: - print() - print("old controllers:") - PrintControllersListProcess(ton, old_controllers) - if user_controllers_list is not None and len(user_controllers_list) > 0: - print() - print("user controllers:") - PrintControllersListProcess(ton, user_controllers_list) -#end define - -def PrintControllersListProcess(ton, controllers): - table = list() - table += [["Address", "Status", "Balance", "Approved", "State"]] - for controllerAddr in controllers: - account = ton.GetAccount(controllerAddr) - controllerData = ton.GetControllerData(controllerAddr) - approved = True if controllerData and controllerData["approved"] == -1 else False - state = controllerData["state"] if controllerData else None - table += [[controllerAddr, account.status, account.balance, approved, state]] - print_table(table) -#end define - -def GetControllerData(ton, args): - try: - controllerAddr = args[0] - except: - color_print("{red}Bad args. Usage:{endc} get_controller_data ") - return - controllerData = ton.GetControllerData(controllerAddr) - print(json.dumps(controllerData, indent=4)) -#end define - -def DepositToController(ton, args): - try: - controllerAddr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} deposit_to_controller ") - return - ton.DepositToController(controllerAddr, amount) -#end define - -def WithdrawFromController(ton, args): - try: - controllerAddr = args[0] - amount = GetItemFromList(args, 1) - except: - color_print("{red}Bad args. Usage:{endc} withdraw_from_controller [amount]") - return - ton.WithdrawFromController(controllerAddr, amount) -#end define - -def CalculateAnnualControllerPercentage(ton, args): - try: - percentPerRound = float(args[0]) - except: - percentPerRound = ton.GetSettings("max_interest_percent") - config15 = ton.GetConfig(15) - roundPeriod = config15["validators_elected_for"] - rounds = 365 * 24 * 3600 / roundPeriod - yearInterest = (1 + percentPerRound / 100) * rounds - yearInterestPercent = round(yearInterest / 100, 2) - print("roundPeriod", roundPeriod) - print("rounds", rounds) - print("percentPerRound", percentPerRound) - print("yearInterest", yearInterest) - print(f"yearInterestPercent: {yearInterestPercent}%") -#end define - -def ControllerUpdateValidatorSet(ton, args): - try: - controllerAddr = args[0] - except: - color_print("{red}Bad args. Usage:{endc} controller_update_validator_set ") - return - ton.ControllerUpdateValidatorSet(controllerAddr) - color_print("ControllerUpdateValidatorSet - {green}OK{endc}") -#end define - -def StopController(ton, args): - try: - controllerAddr = args[0] - except: - color_print("{red}Bad args. Usage:{endc} stop_controller ") - return - ton.StopController(controllerAddr) - color_print("StopController - {green}OK{endc}") -#end define - -def StopAndWithdrawController(ton, args): - try: - controllerAddr = args[0] - amount = GetItemFromList(args, 1) - except: - color_print("{red}Bad args. Usage:{endc} stop_and_withdraw_controller [amount]") - return - if amount is None: - account = ton.GetAccount(controllerAddr) - amount = account.balance-10.1 - ton.StopController(controllerAddr) - ton.WithdrawFromController(controllerAddr, amount) - color_print("StopAndWithdrawController - {green}OK{endc}") -#end define - -def AddController(ton, args): - try: - controllerAddr = args[0] - except: - color_print("{red}Bad args. Usage:{endc} add_controller ") - return - ton.AddController(controllerAddr) - color_print("AddController - {green}OK{endc}") -#end define - -def CheckLiquidPool(ton, args): - ton.CheckLiquidPool() - color_print("CheckLiquidPool - {green}OK{endc}") -#end define - -def CalculateLoanAmount_test(ton, args): - t = ton.CalculateLoanAmount_test() - print(t) - - ### ### Start of the program ### diff --git a/mytonctrl/utils.py b/mytonctrl/utils.py new file mode 100644 index 00000000..01db5491 --- /dev/null +++ b/mytonctrl/utils.py @@ -0,0 +1,5 @@ +def GetItemFromList(data, index): + try: + return data[index] + except: + pass From 24157c61381c2a656e149cab54e36ae5b584b47f Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 4 Mar 2024 13:10:14 +0700 Subject: [PATCH 123/236] improves --- mytoncore/mytoncore.py | 4 ++-- mytonctrl/modules/controller.py | 4 ++-- mytonctrl/mytonctrl.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index c02f19f9..fa6664dd 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3225,9 +3225,9 @@ def enable_mode(self, name): self.local.save() def disable_mode(self, name): - if name not in MODES: - raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') current_modes = self.get_modes() + if name not in current_modes: + raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') current_modes[name] = False self.local.save() diff --git a/mytonctrl/modules/controller.py b/mytonctrl/modules/controller.py index 8875d33d..04b2dd5e 100644 --- a/mytonctrl/modules/controller.py +++ b/mytonctrl/modules/controller.py @@ -1,8 +1,8 @@ import json from mypylib.mypylib import color_print, print_table -from ..utils import GetItemFromList -from .module import MtcModule +from mytonctrl.utils import GetItemFromList +from mytonctrl.modules.module import MtcModule class ControllerModule(MtcModule): diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 4401e0a7..babe6fe1 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -42,7 +42,7 @@ GetBinGitHash, ) from mytonctrl.migrate import run_migrations -from .utils import GetItemFromList +from mytonctrl.utils import GetItemFromList import sys, getopt, os From 390b431c404d800ca87d43907594580202d8dc45 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 5 Mar 2024 13:59:11 +0700 Subject: [PATCH 124/236] modes improves --- mytonctrl/mytonctrl.py | 8 ++++++-- mytonctrl/resources/translate.json | 10 ++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index babe6fe1..4d6d6a65 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -71,6 +71,8 @@ def inject_globals(func): 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("enable_mode", inject_globals(enable_mode), local.translate("enable_mode_cmd")) + console.AddItem("disable_mode", inject_globals(disable_mode), local.translate("disable_mode_cmd")) console.AddItem("seqno", inject_globals(Seqno), local.translate("seqno_cmd")) console.AddItem("getconfig", inject_globals(GetConfig), local.translate("getconfig_cmd")) @@ -1237,7 +1239,7 @@ def SetSettings(ton, args): #end define -def enable_mode(ton, args): +def enable_mode(local, ton, args): try: name = args[0] except: @@ -1245,9 +1247,10 @@ def enable_mode(ton, args): return ton.enable_mode(name) color_print("enable_mode - {green}OK{endc}") + local.exit() -def disable_mode(ton, args): +def disable_mode(local, ton, args): try: name = args[0] except: @@ -1255,6 +1258,7 @@ def disable_mode(ton, args): return ton.disable_mode(name) color_print("disable_mode - {green}OK{endc}") + local.exit() def Xrestart(inputArgs): diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 60350335..854f4dff 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -14,6 +14,16 @@ "ru": "Показать статус TON", "zh_TW": "顯示 TON 狀態" }, + "enable_mode_cmd": { + "en": "Enable mode", + "ru": "Включить режим", + "zh_TW": "啟用模式" + }, + "disable_mode_cmd": { + "en": "Disable mode", + "ru": "Выключить режим", + "zh_TW": "禁用模式" + }, "seqno_cmd": { "en": "Get seqno wallet", "ru": "Получить seqno кошелька", From 6cb38f1cb1ae2dd8e2911d0eb81ecab84f7e90ad Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 12:26:33 +0700 Subject: [PATCH 125/236] add more modes --- mytoncore/functions.py | 4 +- mytoncore/modes.py | 6 +- mytoncore/mytoncore.py | 11 +- mytonctrl/modules/nominator_pool.py | 72 ++++++++ mytonctrl/modules/pool.py | 47 +++++ mytonctrl/modules/single_pool.py | 34 ++++ mytonctrl/mytonctrl.py | 256 ++++------------------------ mytonctrl/resources/translate.json | 5 + 8 files changed, 202 insertions(+), 233 deletions(-) create mode 100644 mytonctrl/modules/nominator_pool.py create mode 100644 mytonctrl/modules/pool.py create mode 100644 mytonctrl/modules/single_pool.py diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 4ca0c3f0..6aad39cb 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -79,8 +79,8 @@ def ValidatorDownEvent(local): def Elections(local, ton): - usePool = local.db.get("usePool") - if usePool == True: + use_pool = ton.using_pool() + if use_pool: ton.PoolsUpdateValidatorSet() ton.RecoverStake() ton.ElectionEntry() diff --git a/mytoncore/modes.py b/mytoncore/modes.py index 62a64a67..67bcff52 100644 --- a/mytoncore/modes.py +++ b/mytoncore/modes.py @@ -1,4 +1,6 @@ MODES = { # mode_name : is_enabled_by_default - 'Controller': False, - 'Validator': True + 'validator': True, + 'nominator-pool': False, + 'single-pool': False, + 'liquid-staking': False, } \ No newline at end of file diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index fa6664dd..f1246abd 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1292,7 +1292,7 @@ def ProcessRecoverStake(self): def GetStake(self, account, args=None): stake = self.local.db.get("stake") - usePool = self.local.db.get("usePool") + usePool = self.using_pool() useController = self.local.db.get("useController") stakePercent = self.local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() @@ -1409,7 +1409,7 @@ def GetValidatorWallet(self, mode="stake"): #end define def ElectionEntry(self, args=None): - usePool = self.local.db.get("usePool") + usePool = self.using_pool() useController = self.local.db.get("useController") wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 @@ -3237,6 +3237,13 @@ def get_mode_value(self, name): raise Exception(f'No mode named {name} found in current modes: {current_modes}') return current_modes[name] + def using_nominator_pool(self): + return (self.local.db.get("usePool") or # for backward compatibility + self.get_mode_value('nominator-pool')) + + def using_pool(self) -> bool: + return self.using_nominator_pool() or self.get_mode_value('single-nominator') + def Tlb2Json(self, text): # Заменить скобки start = 0 diff --git a/mytonctrl/modules/nominator_pool.py b/mytonctrl/modules/nominator_pool.py new file mode 100644 index 00000000..ee07f3d2 --- /dev/null +++ b/mytonctrl/modules/nominator_pool.py @@ -0,0 +1,72 @@ +import os + +from mypylib.mypylib import color_print +from mytonctrl.modules.pool import PoolModule + + +class NominatorPoolModule(PoolModule): + + def new_pool(self, args): + try: + pool_name = args[0] + validator_reward_share_percent = float(args[1]) + max_nominators_count = int(args[2]) + min_validator_stake = int(args[3]) + min_nominator_stake = int(args[4]) + except: + color_print("{red}Bad args. Usage:{endc} new_pool ") + return + self.ton.CreatePool(pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, min_nominator_stake) + color_print("NewPool - {green}OK{endc}") + + def activate_pool(self, args): + try: + pool_name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} activate_pool ") + return + pool = self.ton.GetLocalPool(pool_name) + if not os.path.isfile(pool.bocFilePath): + self.local.add_log(f"Pool {pool_name} already activated", "warning") + return + self.ton.ActivatePool(pool) + color_print("ActivatePool - {green}OK{endc}") + + def deposit_to_pool(self, args): + try: + poll_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") + return + self.ton.DepositToPool(poll_addr, amount) + color_print("DepositToPool - {green}OK{endc}") + + def withdraw_from_pool(self, args): + try: + pool_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") + return + self.ton.WithdrawFromPool(pool_addr, amount) + color_print("WithdrawFromPool - {green}OK{endc}") + + def update_validator_set(self, args): + try: + pool_addr = args[0] + except: + color_print("{red}Bad args. Usage:{endc} update_validator_set ") + return + wallet = self.ton.GetValidatorWallet() + self.ton.PoolUpdateValidatorSet(pool_addr, wallet) + color_print("UpdateValidatorSet - {green}OK{endc}") + + def add_console_commands(self, console): + console.AddItem("new_pool", self.new_pool, self.local.translate("new_pool_cmd")) + console.AddItem("activate_pool", self.activate_pool, self.local.translate("activate_pool_cmd")) + console.AddItem("deposit_to_pool", self.deposit_to_pool, self.local.translate("deposit_to_pool_cmd")) + console.AddItem("withdraw_from_pool", self.withdraw_from_pool, self.local.translate("withdraw_from_pool_cmd")) + console.AddItem("update_validator_set", self.update_validator_set, self.local.translate("update_validator_set_cmd")) + + diff --git a/mytonctrl/modules/pool.py b/mytonctrl/modules/pool.py new file mode 100644 index 00000000..68ba6191 --- /dev/null +++ b/mytonctrl/modules/pool.py @@ -0,0 +1,47 @@ +import os + +from mypylib.mypylib import color_print, print_table +from mytonctrl.modules.module import MtcModule + + +class PoolModule(MtcModule): + + def print_pools_list(self, args): + table = list() + table += [["Name", "Status", "Balance", "Version", "Address"]] + data = self.ton.GetPools() + if data is None or len(data) == 0: + print("No data") + return + for pool in data: + account = self.ton.GetAccount(pool.addrB64) + if account.status != "active": + pool.addrB64 = pool.addrB64_init + version = self.ton.GetVersionFromCodeHash(account.codeHash) + table += [[pool.name, account.status, account.balance, version, pool.addrB64]] + print_table(table) + + def delete_pool(self, args): + try: + pool_name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} delete_pool ") + return + pool = self.ton.GetLocalPool(pool_name) + pool.Delete() + color_print("DeletePool - {green}OK{endc}") + + def import_pool(self, args): + try: + pool_name = args[0] + pool_addr = args[1] + except: + color_print("{red}Bad args. Usage:{endc} import_pool ") + return + self.ton.import_pool(pool_name, pool_addr) + color_print("import_pool - {green}OK{endc}") + + def add_console_commands(self, console): + console.AddItem("pools_list", self.print_pools_list, self.local.translate("pools_list_cmd")) + console.AddItem("delete_pool", self.delete_pool, self.local.translate("delete_pool_cmd")) + console.AddItem("import_pool", self.import_pool, self.local.translate("import_pool_cmd")) diff --git a/mytonctrl/modules/single_pool.py b/mytonctrl/modules/single_pool.py new file mode 100644 index 00000000..434dae0e --- /dev/null +++ b/mytonctrl/modules/single_pool.py @@ -0,0 +1,34 @@ +import os + +from mypylib.mypylib import color_print +from mytonctrl.modules.pool import PoolModule + + +class SingleNominatorModule(PoolModule): + + def new_single_pool(self, args): + try: + pool_name = args[0] + owner_address = args[1] + except: + color_print("{red}Bad args. Usage:{endc} new_single_pool ") + return + self.ton.create_single_pool(pool_name, owner_address) + color_print("new_single_pool - {green}OK{endc}") + + def activate_single_pool(self, args): + try: + pool_name = args[0] + except: + color_print("{red}Bad args. Usage:{endc} activate_single_pool ") + return + pool = self.ton.GetLocalPool(pool_name) + if not os.path.isfile(pool.bocFilePath): + self.local.add_log(f"Pool {pool_name} already activated", "warning") + return + self.ton.activate_single_pool(pool) + color_print("activate_single_pool - {green}OK{endc}") + + def add_console_commands(self, console): + console.AddItem("new_single_pool", self.new_single_pool, self.local.translate("new_single_pool_cmd")) + console.AddItem("activate_single_pool", self.activate_single_pool, self.local.translate("activate_single_pool_cmd")) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 4d6d6a65..f03ab2ab 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -71,6 +71,7 @@ def inject_globals(func): 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("status_modes", inject_globals(mode_status), local.translate("status_modes_cmd")) console.AddItem("enable_mode", inject_globals(enable_mode), local.translate("enable_mode_cmd")) console.AddItem("disable_mode", inject_globals(disable_mode), local.translate("disable_mode_cmd")) console.AddItem("seqno", inject_globals(Seqno), local.translate("seqno_cmd")) @@ -97,11 +98,11 @@ def inject_globals(func): # 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("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")) @@ -121,33 +122,28 @@ def inject_globals(func): #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("new_single_pool", inject_globals(new_single_pool), local.translate("new_single_pool_cmd")) - console.AddItem("activate_single_pool", inject_globals(activate_single_pool), local.translate("activate_single_pool_cmd")) - console.AddItem("import_pool", inject_globals(import_pool), local.translate("import_pool_cmd")) + if ton.using_pool(): + from mytonctrl.modules.pool import PoolModule + module = PoolModule(ton, local) + module.add_console_commands(console) + + if ton.using_nominator_pool(): + from mytonctrl.modules.nominator_pool import NominatorPoolModule + module = NominatorPoolModule(ton, local) + module.add_console_commands(console) - if ton.get_mode_value('Controller'): + if ton.get_mode_value('single-nominator'): + from mytonctrl.modules.single_pool import SingleNominatorModule + module = SingleNominatorModule(ton, local) + module.add_console_commands(console) + + if ton.get_mode_value('liquid-staking'): from mytonctrl.modules.controller import ControllerModule module = ControllerModule(ton, local) module.add_console_commands(console) - # console.AddItem("pt", inject_globals(PrintTest), "PrintTest") - # console.AddItem("sl", inject_globals(sl), "sl") console.AddItem("cleanup", inject_globals(cleanup_validator_db), local.translate("cleanup_cmd")) console.AddItem("benchmark", inject_globals(run_benchmark), local.translate("benchmark_cmd")) @@ -380,6 +376,14 @@ def sl(ton, args): Slashing(ton.local, ton) #end define +def mode_status(ton, args): + modes = ton.get_modes() + text = "########## {bold}Modes{endc} ########## \n" + for mode in modes: + status = '{green}enabled{endc}' if modes[mode] else '{red}disabled{endc}' + text += f"{mode}: {status}\n" + color_print(text) + def PrintStatus(local, ton, args): opt = None if len(args) == 1: @@ -1300,125 +1304,6 @@ 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: - pool_name = args[0] - validatorRewardSharePercent = float(args[1]) - maxNominatorsCount = int(args[2]) - minValidatorStake = int(args[3]) - minNominatorStake = int(args[4]) - except: - color_print("{red}Bad args. Usage:{endc} new_pool ") - return - ton.CreatePool(pool_name, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake) - color_print("NewPool - {green}OK{endc}") -#end define - -def ActivatePool(local, ton, args): - try: - pool_name = args[0] - except: - color_print("{red}Bad args. Usage:{endc} activate_pool ") - return - pool = ton.GetLocalPool(pool_name) - if not os.path.isfile(pool.bocFilePath): - local.add_log(f"Pool {pool_name} already activated", "warning") - return - ton.ActivatePool(pool) - color_print("ActivatePool - {green}OK{endc}") -#end define - -def PrintPoolsList(ton, args): - table = list() - table += [["Name", "Status", "Balance", "Version", "Address"]] - data = ton.GetPools() - if (data is None or len(data) == 0): - print("No data") - return - for pool in data: - account = ton.GetAccount(pool.addrB64) - if account.status != "active": - pool.addrB64 = pool.addrB64_init - version = ton.GetVersionFromCodeHash(account.codeHash) - table += [[pool.name, account.status, account.balance, version, pool.addrB64]] - print_table(table) -#end define - def GetPoolData(ton, args): try: pool_name = args[0] @@ -1432,92 +1317,9 @@ def GetPoolData(ton, args): pool_addr = pool.addrB64 pool_data = ton.GetPoolData(pool_addr) print(json.dumps(pool_data, indent=4)) -#end define - -def DepositToPool(ton, args): - try: - poll_addr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") - return - ton.DepositToPool(poll_addr, amount) - color_print("DepositToPool - {green}OK{endc}") -#end define - -def WithdrawFromPool(ton, args): - try: - pool_addr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") - return - ton.WithdrawFromPool(pool_addr, amount) - color_print("WithdrawFromPool - {green}OK{endc}") -#end define - -def DeletePool(ton, args): - try: - pool_name = args[0] - except: - color_print("{red}Bad args. Usage:{endc} delete_pool ") - return - pool = ton.GetLocalPool(pool_name) - pool.Delete() - color_print("DeletePool - {green}OK{endc}") -#end define - -def UpdateValidatorSet(ton, args): - try: - pool_addr = args[0] - except: - color_print("{red}Bad args. Usage:{endc} update_validator_set ") - return - wallet = ton.GetValidatorWallet() - ton.PoolUpdateValidatorSet(pool_addr, wallet) - color_print("UpdateValidatorSet - {green}OK{endc}") -#end define - -def new_single_pool(ton, args): - try: - pool_name = args[0] - owner_address = args[1] - except: - color_print("{red}Bad args. Usage:{endc} new_single_pool ") - return - ton.create_single_pool(pool_name, owner_address) - color_print("new_single_pool - {green}OK{endc}") -#end define - -def activate_single_pool(local, ton, args): - try: - pool_name = args[0] - except: - color_print("{red}Bad args. Usage:{endc} activate_single_pool ") - return - pool = ton.GetLocalPool(pool_name) - if not os.path.isfile(pool.bocFilePath): - local.add_log(f"Pool {pool_name} already activated", "warning") - return - ton.activate_single_pool(pool) - color_print("activate_single_pool - {green}OK{endc}") -#end define -def import_pool(ton, args): - try: - pool_name = args[0] - pool_addr = args[1] - except: - color_print("{red}Bad args. Usage:{endc} import_pool ") - return - ton.import_pool(pool_name, pool_addr) - color_print("import_pool - {green}OK{endc}") -#end define -### ### Start of the program -### - def mytonctrl(): local = MyPyClass('mytonctrl.py') mytoncore_local = MyPyClass('mytoncore.py') diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 854f4dff..3ab39316 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -14,6 +14,11 @@ "ru": "Показать статус TON", "zh_TW": "顯示 TON 狀態" }, + "status_modes_cmd": { + "en": "Show MTC modes", + "ru": "Показать режимы MTC", + "zh_TW": "顯示 MTC 模式" + }, "enable_mode_cmd": { "en": "Enable mode", "ru": "Включить режим", From 62cfb0236772fd15fbb2621112e9994f7f61d078 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 12:45:20 +0700 Subject: [PATCH 126/236] rm nominationController --- mytoncore/mytoncore.py | 107 +---------------------------------------- 1 file changed, 2 insertions(+), 105 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index f1246abd..fad97edc 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1363,48 +1363,10 @@ 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 = get_timestamp() - 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"): 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) + walletName = self.local.db.get("validatorWalletName") + wallet = self.GetLocalWallet(walletName) return wallet #end define @@ -3421,71 +3383,6 @@ 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): self.local.add_log("start CreatePool function", "debug") validatorRewardShare = int(validatorRewardSharePercent * 100) From 5bb21ba66a361b95ebd020225c56bdd0d92249e8 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 13:10:33 +0700 Subject: [PATCH 127/236] add validator mode --- mytoncore/functions.py | 13 +++---- mytoncore/mytoncore.py | 15 +++++-- mytonctrl/modules/validator.py | 34 ++++++++++++++++ mytonctrl/mytonctrl.py | 71 ++++++++++++---------------------- 4 files changed, 75 insertions(+), 58 deletions(-) create mode 100644 mytonctrl/modules/validator.py diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 6aad39cb..42336cc2 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -82,12 +82,9 @@ def Elections(local, ton): use_pool = ton.using_pool() if use_pool: ton.PoolsUpdateValidatorSet() - ton.RecoverStake() + ton.RecoverStake() + if ton.using_validator(): ton.ElectionEntry() - else: - ton.RecoverStake() - ton.ElectionEntry() -# end define def Statistics(local): @@ -516,10 +513,10 @@ def Complaints(local, ton): def Slashing(local, ton): - isSlashing = local.db.get("isSlashing") - if isSlashing is not True: + is_slashing = local.db.get("isSlashing") + is_validator = ton.using_validator() + if is_slashing is not True or is_validator: return - # end if # Creating complaints slash_time = local.buffer.slash_time diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index fad97edc..89d050f2 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1293,7 +1293,7 @@ def ProcessRecoverStake(self): def GetStake(self, account, args=None): stake = self.local.db.get("stake") usePool = self.using_pool() - useController = self.local.db.get("useController") + useController = self.local.db.get("useController") or self.using_liquid_staking() stakePercent = self.local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() validators = vconfig.get("validators") @@ -1372,7 +1372,7 @@ def GetValidatorWallet(self, mode="stake"): def ElectionEntry(self, args=None): usePool = self.using_pool() - useController = self.local.db.get("useController") + useController = self.local.db.get("useController") or self.using_liquid_staking() wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 if wallet is None: @@ -3203,8 +3203,17 @@ def using_nominator_pool(self): return (self.local.db.get("usePool") or # for backward compatibility self.get_mode_value('nominator-pool')) + def using_single_nominator(self): + return self.get_mode_value('single-nominator') + + def using_liquid_staking(self): + return self.get_mode_value('liquid-staking') + def using_pool(self) -> bool: - return self.using_nominator_pool() or self.get_mode_value('single-nominator') + return self.using_nominator_pool() or self.using_single_nominator() + + def using_validator(self): + return self.get_mode_value('validator') def Tlb2Json(self, text): # Заменить скобки diff --git a/mytonctrl/modules/validator.py b/mytonctrl/modules/validator.py new file mode 100644 index 00000000..05fc71ae --- /dev/null +++ b/mytonctrl/modules/validator.py @@ -0,0 +1,34 @@ +from mypylib.mypylib import color_print +from mytonctrl.modules.module import MtcModule + +from mytoncore.functions import Elections + + +class ValidatorModule(MtcModule): + + def vote_offer(self, args): + if len(args) == 0: + color_print("{red}Bad args. Usage:{endc} vo ") + return + for offerHash in args: + self.ton.VoteOffer(offerHash) + color_print("VoteOffer - {green}OK{endc}") + + def vote_election_entry(self, args): + Elections(self.ton.local, self.ton) + color_print("VoteElectionEntry - {green}OK{endc}") + + def vote_complaint(self, args): + try: + election_id = args[0] + complaint_hash = args[1] + except: + color_print("{red}Bad args. Usage:{endc} vc ") + return + self.ton.VoteComplaint(election_id, complaint_hash) + color_print("VoteComplaint - {green}OK{endc}") + + def add_console_commands(self, console): + console.AddItem("vo", self.vote_offer, self.local.translate("vo_cmd")) + console.AddItem("ve", self.vote_election_entry, self.local.translate("ve_cmd")) + console.AddItem("vc", self.vote_complaint, self.local.translate("vc_cmd")) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index f03ab2ab..77a92d5d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -74,8 +74,12 @@ def inject_globals(func): console.AddItem("status_modes", inject_globals(mode_status), local.translate("status_modes_cmd")) console.AddItem("enable_mode", inject_globals(enable_mode), local.translate("enable_mode_cmd")) console.AddItem("disable_mode", inject_globals(disable_mode), local.translate("disable_mode_cmd")) + console.AddItem("get", inject_globals(GetSettings), local.translate("get_cmd")) + console.AddItem("set", inject_globals(SetSettings), local.translate("set_cmd")) + console.AddItem("seqno", inject_globals(Seqno), local.translate("seqno_cmd")) console.AddItem("getconfig", inject_globals(GetConfig), local.translate("getconfig_cmd")) + console.AddItem("get_pool_data", inject_globals(GetPoolData), local.translate("get_pool_data_cmd")) console.AddItem("nw", inject_globals(CreatNewWallet), local.translate("nw_cmd")) console.AddItem("aw", inject_globals(ActivateWallet), local.translate("aw_cmd")) @@ -105,44 +109,42 @@ def inject_globals(func): # 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("get_pool_data", inject_globals(GetPoolData), local.translate("get_pool_data_cmd")) - - if ton.using_pool(): - from mytonctrl.modules.pool import PoolModule - module = PoolModule(ton, local) + if ton.get_mode_value('validator'): + from mytonctrl.modules.validator import ValidatorModule + module = ValidatorModule(ton, local) module.add_console_commands(console) - if ton.using_nominator_pool(): - from mytonctrl.modules.nominator_pool import NominatorPoolModule - module = NominatorPoolModule(ton, local) - module.add_console_commands(console) + if ton.using_pool(): # add basic pool functions (pools_list, delete_pool, import_pool) + from mytonctrl.modules.pool import PoolModule + module = PoolModule(ton, local) + module.add_console_commands(console) - if ton.get_mode_value('single-nominator'): - from mytonctrl.modules.single_pool import SingleNominatorModule - module = SingleNominatorModule(ton, local) - module.add_console_commands(console) + if ton.using_nominator_pool(): + from mytonctrl.modules.nominator_pool import NominatorPoolModule + module = NominatorPoolModule(ton, local) + module.add_console_commands(console) - if ton.get_mode_value('liquid-staking'): - from mytonctrl.modules.controller import ControllerModule - module = ControllerModule(ton, local) - module.add_console_commands(console) + if ton.get_mode_value('single-nominator'): + from mytonctrl.modules.single_pool import SingleNominatorModule + module = SingleNominatorModule(ton, local) + module.add_console_commands(console) + + if ton.using_liquid_staking(): + from mytonctrl.modules.controller import ControllerModule + module = ControllerModule(ton, local) + module.add_console_commands(console) console.AddItem("cleanup", inject_globals(cleanup_validator_db), local.translate("cleanup_cmd")) console.AddItem("benchmark", inject_globals(run_benchmark), local.translate("benchmark_cmd")) @@ -1000,15 +1002,6 @@ def PrintOffersList(ton, args): print_table(table) #end define -def VoteOffer(ton, args): - if len(args) == 0: - color_print("{red}Bad args. Usage:{endc} vo ") - return - for offerHash in args: - ton.VoteOffer(offerHash) - color_print("VoteOffer - {green}OK{endc}") -#end define - def OfferDiff(ton, args): try: offerHash = args[0] @@ -1063,17 +1056,6 @@ def PrintComplaintsList(ton, args): print_table(table) #end define -def VoteComplaint(ton, args): - try: - electionId = args[0] - complaintHash = args[1] - except: - color_print("{red}Bad args. Usage:{endc} vc ") - return - ton.VoteComplaint(electionId, complaintHash) - color_print("VoteComplaint - {green}OK{endc}") -#end define - def NewDomain(ton, args): try: domainName = args[0] @@ -1172,11 +1154,6 @@ def PrintElectionEntriesList(ton, args): print_table(table) #end define -def VoteElectionEntry(ton, args): - Elections(ton.local, ton) - color_print("VoteElectionEntry - {green}OK{endc}") -#end define - def PrintValidatorList(ton, args): past = "past" in args data = ton.GetValidatorsList(past=past) From cfeda1c10193c59a34939d21108ac3dd35ab7082 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 13:18:41 +0700 Subject: [PATCH 128/236] fix controller --- mytoncore/mytoncore.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 89d050f2..2420a31f 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1131,10 +1131,10 @@ def PrepareComplaint(self, electionId, inputFileName): return fileName #end define - def CreateElectionRequest(self, wallet, startWorkTime, adnlAddr, maxFactor): + def CreateElectionRequest(self, addrB64, startWorkTime, adnlAddr, maxFactor): 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] + args = ["validator-elect-req.fif", addrB64, startWorkTime, maxFactor, adnlAddr, fileName] result = self.fift.Run(args) fileName = parse(result, "Saved to file ", '\n') resultList = result.split('\n') @@ -1319,7 +1319,7 @@ def GetStake(self, account, args=None): #end if pool_version = self.GetVersionFromCodeHash(account.codeHash) - is_single_nominator = 'spool' in pool_version + is_single_nominator = pool_version is not None and 'spool' in pool_version if stake is None and usePool and not is_single_nominator: stake = account.balance - 20 @@ -1457,7 +1457,7 @@ def ElectionEntry(self, args=None): # Create fift's. Continue with pool or walet if usePool: - var1 = self.CreateElectionRequest(pool, startWorkTime, adnl_addr, maxFactor) + var1 = self.CreateElectionRequest(pool.addrB64, startWorkTime, adnl_addr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) validatorPubkey, resultFilePath = self.SignElectionRequestWithPoolWithValidator(pool, startWorkTime, adnl_addr, validatorPubkey_b64, validatorSignature, maxFactor, stake) @@ -1473,7 +1473,7 @@ def ElectionEntry(self, args=None): resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, controllerAddr, 1.03) self.SendFile(resultFilePath, wallet) else: - var1 = self.CreateElectionRequest(wallet, startWorkTime, adnl_addr, maxFactor) + var1 = self.CreateElectionRequest(wallet.addrB64, startWorkTime, adnl_addr, maxFactor) validatorSignature = self.GetValidatorSignature(validatorKey, var1) validatorPubkey, resultFilePath = self.SignElectionRequestWithValidator(wallet, startWorkTime, adnl_addr, validatorPubkey_b64, validatorSignature, maxFactor) @@ -4022,7 +4022,7 @@ def CheckLiquidPool(self): for controllerAddr in addrs_list: account = self.GetAccount(controllerAddr) - version = self.GetWalletVersionFromHash(account.codeHash) + version = self.GetVersionFromCodeHash(account.codeHash) if version is None or "controller" not in version: continue print(f"check controller: {controllerAddr}") From 7f78be20612be00d98194a8cfb08d2ff93033d8a Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 13:56:26 +0700 Subject: [PATCH 129/236] move some functions from mytoncore.py to mytonctrl/modules --- mytoncore/functions.py | 3 + mytoncore/mytoncore.py | 173 +--------------------------- mytonctrl/modules/controller.py | 108 +++++++++++++++-- mytonctrl/modules/nominator_pool.py | 34 +++++- mytonctrl/modules/single_pool.py | 37 +++++- 5 files changed, 174 insertions(+), 181 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 42336cc2..841a6d3f 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -80,8 +80,11 @@ def ValidatorDownEvent(local): def Elections(local, ton): use_pool = ton.using_pool() + use_liquid_staking = ton.using_liquid_staking() if use_pool: ton.PoolsUpdateValidatorSet() + if use_liquid_staking: + ton.ControllersUpdateValidatorSet() ton.RecoverStake() if ton.using_validator(): ton.ElectionEntry() diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 2420a31f..2700de49 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1293,7 +1293,7 @@ def ProcessRecoverStake(self): def GetStake(self, account, args=None): stake = self.local.db.get("stake") usePool = self.using_pool() - useController = self.local.db.get("useController") or self.using_liquid_staking() + useController = self.using_liquid_staking() stakePercent = self.local.db.get("stakePercent", 99) vconfig = self.GetValidatorConfig() validators = vconfig.get("validators") @@ -1372,7 +1372,7 @@ def GetValidatorWallet(self, mode="stake"): def ElectionEntry(self, args=None): usePool = self.using_pool() - useController = self.local.db.get("useController") or self.using_liquid_staking() + useController = self.using_liquid_staking() wallet = self.GetValidatorWallet() addrB64 = wallet.addrB64 if wallet is None: @@ -3207,7 +3207,8 @@ def using_single_nominator(self): return self.get_mode_value('single-nominator') def using_liquid_staking(self): - return self.get_mode_value('liquid-staking') + return (self.local.db.get("useController") or # for backward compatibility + self.get_mode_value('liquid-staking')) def using_pool(self) -> bool: return self.using_nominator_pool() or self.using_single_nominator() @@ -3423,36 +3424,6 @@ def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, #end for #end define - def ActivatePool(self, pool, ex=True): - self.local.add_log("start ActivatePool function", "debug") - for i in range(10): - time.sleep(3) - account = self.GetAccount(pool.addrB64) - if account.balance > 0: - self.SendFile(pool.bocFilePath, pool, timeout=False) - return - if ex: - raise Exception("ActivatePool error: time out") - #end define - - def DepositToPool(self, poolAddr, amount): - wallet = self.GetValidatorWallet() - 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) - resultFilePath = self.SignBocWithWallet(wallet, bocPath, poolAddr, amount) - self.SendFile(resultFilePath, wallet) - #end define - - def WithdrawFromPool(self, poolAddr, amount): - poolData = self.GetPoolData(poolAddr) - if poolData["state"] == 0: - self.WithdrawFromPoolProcess(poolAddr, amount) - else: - self.PendWithdrawFromPool(poolAddr, amount) - #end define - def WithdrawFromPoolProcess(self, poolAddr, amount): self.local.add_log("start WithdrawFromPoolProcess function", "debug") wallet = self.GetValidatorWallet() @@ -3642,35 +3613,6 @@ def GetLiquidPoolAddr(self): return liquid_pool_addr #end define - def CreateControllers(self): - new_controllers = self.GetControllers() - old_controllers = self.local.db.get("using_controllers", list()) - if new_controllers == old_controllers: - return - #end if - - self.local.add_log("start CreateControllers function", "debug") - wallet = self.GetValidatorWallet() - liquid_pool_addr = self.GetLiquidPoolAddr() - contractPath = self.contractsDir + "jetton_pool/" - if not os.path.isdir(contractPath): - self.DownloadContract("https://github.com/igroman787/jetton_pool") - #end if - - fileName0 = contractPath + "fift-scripts/deploy_controller0.boc" - fileName1 = contractPath + "fift-scripts/deploy_controller1.boc" - resultFilePath0 = self.SignBocWithWallet(wallet, fileName0, liquid_pool_addr, 1) - self.SendFile(resultFilePath0, wallet) - time.sleep(10) - resultFilePath1 = self.SignBocWithWallet(wallet, fileName1, liquid_pool_addr, 1) - self.SendFile(resultFilePath1, wallet) - - # Сохранить новые контроллеры - self.local.db["old_controllers"] = old_controllers - self.local.db["using_controllers"] = new_controllers - self.local.save() - #end define - def GetControllerAddress(self, controller_id): wallet = self.GetValidatorWallet() addr_hash = HexAddr2Dec(wallet.addr) @@ -3817,14 +3759,6 @@ def CalculateLoanAmount(self, min_loan, max_loan, max_interest): return result #end define - def CalculateLoanAmount_test(self): - min_loan = self.local.db.get("min_loan", 41000) - max_loan = self.local.db.get("max_loan", 43000) - max_interest_percent = self.local.db.get("max_interest_percent", 1.5) - max_interest = int(max_interest_percent/100*16777216) - return self.CalculateLoanAmount(min_loan, max_loan, max_interest) - #end define - def WaitLoan(self, controllerAddr): self.local.add_log("start WaitLoan function", "debug") for i in range(10): @@ -3843,14 +3777,6 @@ def ReturnUnusedLoan(self, controllerAddr): self.SendFile(resultFilePath, wallet) #end define - def DepositToController(self, controllerAddr, amount): - self.local.add_log("start DepositToController function", "debug") - wallet = self.GetValidatorWallet() - fileName = self.contractsDir + "jetton_pool/fift-scripts/top-up.boc" - resultFilePath = self.SignBocWithWallet(wallet, fileName, controllerAddr, amount) - self.SendFile(resultFilePath, wallet) - #end define - def WithdrawFromController(self, controllerAddr, amount=None): controllerData = self.GetControllerData(controllerAddr) if controllerData["state"] == 0: @@ -3973,97 +3899,6 @@ def ControllerRecoverStake(self, controllerAddr): self.local.add_log("ControllerRecoverStake completed") #end define - def StopController(self, controllerAddr): - stop_controllers_list = self.local.db.get("stop_controllers_list") - if stop_controllers_list is None: - stop_controllers_list = list() - if controllerAddr not in stop_controllers_list: - stop_controllers_list.append(controllerAddr) - self.local.db["stop_controllers_list"] = stop_controllers_list - - user_controllers = self.local.db.get("user_controllers") - if user_controllers is not None and controllerAddr in user_controllers: - user_controllers.remove(controllerAddr) - self.local.save() - #end define - - def AddController(self, controllerAddr): - user_controllers = self.local.db.get("user_controllers") - if user_controllers is None: - user_controllers = list() - if controllerAddr not in user_controllers: - user_controllers.append(controllerAddr) - self.local.db["user_controllers"] = user_controllers - - stop_controllers_list = self.local.db.get("stop_controllers_list") - if stop_controllers_list is not None and controllerAddr in stop_controllers_list: - stop_controllers_list.remove(controllerAddr) - self.local.save() - #end define - - def CheckLiquidPool(self): - liquid_pool_addr = self.GetLiquidPoolAddr() - account = self.GetAccount(liquid_pool_addr) - history = self.GetAccountHistory(account, 5000) - addrs_list = list() - for message in history: - if message.srcAddr is None or message.value is None: - continue - srcAddrFull = f"{message.srcWorkchain}:{message.srcAddr}" - destAddFull = f"{message.destWorkchain}:{message.destAddr}" - if srcAddrFull == account.addrFull: - fromto = destAddFull - else: - fromto = srcAddrFull - fromto = self.AddrFull2AddrB64(fromto) - if fromto not in addrs_list: - addrs_list.append(fromto) - #end for - - for controllerAddr in addrs_list: - account = self.GetAccount(controllerAddr) - version = self.GetVersionFromCodeHash(account.codeHash) - if version is None or "controller" not in version: - continue - print(f"check controller: {controllerAddr}") - self.ControllerUpdateValidatorSet(controllerAddr) - #end define - - def create_single_pool(self, pool_name, owner_address): - self.local.add_log("start create_single_pool function", "debug") - - file_path = self.poolsDir + pool_name - if os.path.isfile(file_path + ".addr"): - self.local.add_log("create_single_pool warning: Pool already exists: " + file_path, "warning") - return - #end if - - fift_script = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/init.fif') - code_boc = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/single-nominator-code.hex') - validator_wallet = self.GetValidatorWallet() - args = [fift_script, code_boc, owner_address, validator_wallet.addrB64, file_path] - result = self.fift.Run(args) - if "Saved single nominator pool" not in result: - raise Exception("create_single_pool error: " + result) - #end if - - pools = self.GetPools() - new_pool = self.GetLocalPool(pool_name) - for pool in pools: - if pool.name != new_pool.name and pool.addrB64 == new_pool.addrB64: - new_pool.Delete() - raise Exception("create_single_pool error: Pool with the same parameters already exists.") - #end for - #end define - - def activate_single_pool(self, pool): - self.local.add_log("start activate_single_pool function", "debug") - boc_mode = "--with-init" - validator_wallet = self.GetValidatorWallet() - resultFilePath = self.SignBocWithWallet(validator_wallet, pool.bocFilePath, pool.addrB64_init, 1, boc_mode=boc_mode) - self.SendFile(resultFilePath, validator_wallet) - #end define - def GetNetworkName(self): data = self.local.read_db(self.liteClient.configPath) mainnet_zero_state_root_hash = "F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=" diff --git a/mytonctrl/modules/controller.py b/mytonctrl/modules/controller.py index 04b2dd5e..be859ae4 100644 --- a/mytonctrl/modules/controller.py +++ b/mytonctrl/modules/controller.py @@ -1,4 +1,7 @@ import json +import os +import time + from mypylib.mypylib import color_print, print_table from mytonctrl.utils import GetItemFromList @@ -7,8 +10,33 @@ class ControllerModule(MtcModule): + def do_create_controllers(self): + new_controllers = self.ton.GetControllers() + old_controllers = self.ton.local.db.get("using_controllers", list()) + if new_controllers == old_controllers: + return + + self.ton.local.add_log("start CreateControllers function", "debug") + wallet = self.ton.GetValidatorWallet() + liquid_pool_addr = self.ton.GetLiquidPoolAddr() + contract_path = self.ton.contractsDir + "jetton_pool/" + if not os.path.isdir(contract_path): + self.ton.DownloadContract("https://github.com/igroman787/jetton_pool") + + file_name0 = contract_path + "fift-scripts/deploy_controller0.boc" + file_name1 = contract_path + "fift-scripts/deploy_controller1.boc" + result_file_path0 = self.ton.SignBocWithWallet(wallet, file_name0, liquid_pool_addr, 1) + self.ton.SendFile(result_file_path0, wallet) + time.sleep(10) + result_file_path1 = self.ton.SignBocWithWallet(wallet, file_name1, liquid_pool_addr, 1) + self.ton.SendFile(result_file_path1, wallet) + + self.ton.local.db["old_controllers"] = old_controllers + self.ton.local.db["using_controllers"] = new_controllers + self.ton.local.save() + def create_controllers(self, args): - self.ton.CreateControllers() + self.do_create_controllers() color_print("CreateControllers - {green}OK{endc}") def print_controllers_list(self, args): @@ -51,6 +79,13 @@ def get_controller_data(self, args): controller_data = self.ton.GetControllerData(controller_addr) print(json.dumps(controller_data, indent=4)) + def do_deposit_to_controller(self, controller_addr, amount): + self.ton.local.add_log("start DepositToController function", "debug") + wallet = self.ton.GetValidatorWallet() + file_name = self.ton.contractsDir + "jetton_pool/fift-scripts/top-up.boc" + result_file_path = self.ton.SignBocWithWallet(wallet, file_name, controller_addr, amount) + self.ton.SendFile(result_file_path, wallet) + def deposit_to_controller(self, args): try: controller_addr = args[0] @@ -58,7 +93,7 @@ def deposit_to_controller(self, args): except: color_print("{red}Bad args. Usage:{endc} deposit_to_controller ") return - self.ton.DepositToController(controller_addr, amount) + self.do_deposit_to_controller(controller_addr, amount) def withdraw_from_controller(self, args): try: @@ -94,13 +129,26 @@ def controller_update_validator_set(self, args): self.ton.ControllerUpdateValidatorSet(controller_addr) color_print("ControllerUpdateValidatorSet - {green}OK{endc}") + def do_stop_controller(self, controller_addr): + stop_controllers_list = self.ton.local.db.get("stop_controllers_list") + if stop_controllers_list is None: + stop_controllers_list = list() + if controller_addr not in stop_controllers_list: + stop_controllers_list.append(controller_addr) + self.ton.local.db["stop_controllers_list"] = stop_controllers_list + + user_controllers = self.ton.local.db.get("user_controllers") + if user_controllers is not None and controller_addr in user_controllers: + user_controllers.remove(controller_addr) + self.ton.local.save() + def stop_controller(self, args): try: controller_addr = args[0] except: color_print("{red}Bad args. Usage:{endc} stop_controller ") return - self.ton.StopController(controller_addr) + self.do_stop_controller(controller_addr) color_print("StopController - {green}OK{endc}") def stop_and_withdraw_controller(self, args): @@ -113,25 +161,71 @@ def stop_and_withdraw_controller(self, args): if amount is None: account = self.ton.GetAccount(controller_addr) amount = account.balance - 10.1 - self.ton.StopController(controller_addr) + self.do_stop_controller(controller_addr) self.ton.WithdrawFromController(controller_addr, amount) color_print("StopAndWithdrawController - {green}OK{endc}") + def do_add_controller(self, controller_addr): + user_controllers = self.ton.local.db.get("user_controllers") + if user_controllers is None: + user_controllers = list() + if controller_addr not in user_controllers: + user_controllers.append(controller_addr) + self.ton.local.db["user_controllers"] = user_controllers + + stop_controllers_list = self.ton.local.db.get("stop_controllers_list") + if stop_controllers_list is not None and controller_addr in stop_controllers_list: + stop_controllers_list.remove(controller_addr) + self.ton.local.save() + def add_controller(self, args): try: controller_addr = args[0] except: color_print("{red}Bad args. Usage:{endc} add_controller ") return - self.ton.AddController(controller_addr) + self.do_add_controller(controller_addr) color_print("AddController - {green}OK{endc}") + def do_check_liquid_pool(self): + liquid_pool_addr = self.ton.GetLiquidPoolAddr() + account = self.ton.GetAccount(liquid_pool_addr) + history = self.ton.GetAccountHistory(account, 5000) + addrs_list = list() + for message in history: + if message.srcAddr is None or message.value is None: + continue + src_addr_full = f"{message.srcWorkchain}:{message.srcAddr}" + dest_add_full = f"{message.destWorkchain}:{message.destAddr}" + if src_addr_full == account.addrFull: + fromto = dest_add_full + else: + fromto = src_addr_full + fromto = self.ton.AddrFull2AddrB64(fromto) + if fromto not in addrs_list: + addrs_list.append(fromto) + + for controllerAddr in addrs_list: + account = self.ton.GetAccount(controllerAddr) + version = self.ton.GetVersionFromCodeHash(account.codeHash) + if version is None or "controller" not in version: + continue + print(f"check controller: {controllerAddr}") + self.ton.ControllerUpdateValidatorSet(controllerAddr) + def check_liquid_pool(self, args): - self.ton.CheckLiquidPool() + self.do_check_liquid_pool() color_print("CheckLiquidPool - {green}OK{endc}") + def do_calculate_loan_amount_test(self): + min_loan = self.ton.local.db.get("min_loan", 41000) + max_loan = self.ton.local.db.get("max_loan", 43000) + max_interest_percent = self.ton.local.db.get("max_interest_percent", 1.5) + max_interest = int(max_interest_percent / 100 * 16777216) + return self.ton.CalculateLoanAmount(min_loan, max_loan, max_interest) + def calculate_loan_amount_test(self, args): - t = self.ton.CalculateLoanAmount_test() + t = self.do_calculate_loan_amount_test() print(t) def add_console_commands(self, console): diff --git a/mytonctrl/modules/nominator_pool.py b/mytonctrl/modules/nominator_pool.py index ee07f3d2..9a632209 100644 --- a/mytonctrl/modules/nominator_pool.py +++ b/mytonctrl/modules/nominator_pool.py @@ -1,4 +1,5 @@ import os +import time from mypylib.mypylib import color_print from mytonctrl.modules.pool import PoolModule @@ -19,6 +20,17 @@ def new_pool(self, args): self.ton.CreatePool(pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, min_nominator_stake) color_print("NewPool - {green}OK{endc}") + def do_activate_pool(self, pool, ex=True): + self.ton.local.add_log("start ActivatePool function", "debug") + for i in range(10): + time.sleep(3) + account = self.ton.GetAccount(pool.addrB64) + if account.balance > 0: + self.ton.SendFile(pool.bocFilePath, pool, timeout=False) + return + if ex: + raise Exception("ActivatePool error: time out") + def activate_pool(self, args): try: pool_name = args[0] @@ -29,9 +41,18 @@ def activate_pool(self, args): if not os.path.isfile(pool.bocFilePath): self.local.add_log(f"Pool {pool_name} already activated", "warning") return - self.ton.ActivatePool(pool) + self.do_activate_pool(pool) color_print("ActivatePool - {green}OK{endc}") + def do_deposit_to_pool(self, pool_addr, amount): + wallet = self.ton.GetValidatorWallet() + bocPath = self.ton.local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" + fiftScript = self.ton.contractsDir + "nominator-pool/func/validator-deposit.fif" + args = [fiftScript, bocPath] + result = self.ton.fift.Run(args) + resultFilePath = self.ton.SignBocWithWallet(wallet, bocPath, pool_addr, amount) + self.ton.SendFile(resultFilePath, wallet) + def deposit_to_pool(self, args): try: poll_addr = args[0] @@ -39,9 +60,16 @@ def deposit_to_pool(self, args): except: color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") return - self.ton.DepositToPool(poll_addr, amount) + self.do_deposit_to_pool(poll_addr, amount) color_print("DepositToPool - {green}OK{endc}") + def do_withdraw_from_pool(self, pool_addr, amount): + pool_data = self.ton.GetPoolData(pool_addr) + if pool_data["state"] == 0: + self.ton.WithdrawFromPoolProcess(pool_addr, amount) + else: + self.ton.PendWithdrawFromPool(pool_addr, amount) + def withdraw_from_pool(self, args): try: pool_addr = args[0] @@ -49,7 +77,7 @@ def withdraw_from_pool(self, args): except: color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") return - self.ton.WithdrawFromPool(pool_addr, amount) + self.do_withdraw_from_pool(pool_addr, amount) color_print("WithdrawFromPool - {green}OK{endc}") def update_validator_set(self, args): diff --git a/mytonctrl/modules/single_pool.py b/mytonctrl/modules/single_pool.py index 434dae0e..5cd60ee4 100644 --- a/mytonctrl/modules/single_pool.py +++ b/mytonctrl/modules/single_pool.py @@ -1,11 +1,37 @@ import os +import pkg_resources + from mypylib.mypylib import color_print from mytonctrl.modules.pool import PoolModule class SingleNominatorModule(PoolModule): + def do_create_single_pool(self, pool_name, owner_address): + self.ton.local.add_log("start create_single_pool function", "debug") + + file_path = self.ton.poolsDir + pool_name + if os.path.isfile(file_path + ".addr"): + self.ton.local.add_log("create_single_pool warning: Pool already exists: " + file_path, "warning") + return + + fift_script = pkg_resources.resource_filename('mytoncore', 'contracts/single-nominator-pool/init.fif') + code_boc = pkg_resources.resource_filename('mytoncore', + 'contracts/single-nominator-pool/single-nominator-code.hex') + validator_wallet = self.ton.GetValidatorWallet() + args = [fift_script, code_boc, owner_address, validator_wallet.addrB64, file_path] + result = self.ton.fift.Run(args) + if "Saved single nominator pool" not in result: + raise Exception("create_single_pool error: " + result) + + pools = self.ton.GetPools() + new_pool = self.ton.GetLocalPool(pool_name) + for pool in pools: + if pool.name != new_pool.name and pool.addrB64 == new_pool.addrB64: + new_pool.Delete() + raise Exception("create_single_pool error: Pool with the same parameters already exists.") + def new_single_pool(self, args): try: pool_name = args[0] @@ -13,9 +39,16 @@ def new_single_pool(self, args): except: color_print("{red}Bad args. Usage:{endc} new_single_pool ") return - self.ton.create_single_pool(pool_name, owner_address) + self.do_create_single_pool(pool_name, owner_address) color_print("new_single_pool - {green}OK{endc}") + def do_activate_single_pool(self, pool): + self.local.add_log("start activate_single_pool function", "debug") + boc_mode = "--with-init" + validator_wallet = self.ton.GetValidatorWallet() + result_file_path = self.ton.SignBocWithWallet(validator_wallet, pool.bocFilePath, pool.addrB64_init, 1, boc_mode=boc_mode) + self.ton.SendFile(result_file_path, validator_wallet) + def activate_single_pool(self, args): try: pool_name = args[0] @@ -26,7 +59,7 @@ def activate_single_pool(self, args): if not os.path.isfile(pool.bocFilePath): self.local.add_log(f"Pool {pool_name} already activated", "warning") return - self.ton.activate_single_pool(pool) + self.do_activate_single_pool(pool) color_print("activate_single_pool - {green}OK{endc}") def add_console_commands(self, console): From 28d264e6e85e5e382f9f8ebfbcfa76523d4f9b30 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 17:55:07 +0700 Subject: [PATCH 130/236] bugfix --- mytoncore/functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 841a6d3f..4a640e4b 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -518,7 +518,7 @@ def Complaints(local, ton): def Slashing(local, ton): is_slashing = local.db.get("isSlashing") is_validator = ton.using_validator() - if is_slashing is not True or is_validator: + if is_slashing is not True or not is_validator: return # Creating complaints From cc91ccc8e6751149ec0be60094547a768f0bc761 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 6 Mar 2024 18:22:08 +0700 Subject: [PATCH 131/236] bugfix --- mytoncore/modes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/modes.py b/mytoncore/modes.py index 67bcff52..d9d76382 100644 --- a/mytoncore/modes.py +++ b/mytoncore/modes.py @@ -1,6 +1,6 @@ MODES = { # mode_name : is_enabled_by_default 'validator': True, 'nominator-pool': False, - 'single-pool': False, + 'single-nominator': False, 'liquid-staking': False, } \ No newline at end of file From 4fca7aaa6c69478aa823a7f69b54a6068360025b Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 8 Mar 2024 12:56:42 +0700 Subject: [PATCH 132/236] refactor complaints validation --- mytoncore/functions.py | 9 +-- mytoncore/mytoncore.py | 123 ++++++++++++++++++----------------------- 2 files changed, 59 insertions(+), 73 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 4a640e4b..98b8098d 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -506,12 +506,13 @@ def Complaints(local, ton): # Voting for complaints config32 = ton.GetConfig32() - electionId = config32.get("startWorkTime") - complaints = ton.GetComplaints(electionId) # get complaints from Elector - for c in complaints.values(): + election_id = config32.get("startWorkTime") + complaints = ton.GetComplaints(election_id) # get complaints from Elector + valid_complaints = ton.get_valid_complaints(complaints, election_id) + for c in valid_complaints.values(): complaint_hash = c.get("hash") if ton.complaint_is_valid(c): - ton.VoteComplaint(electionId, complaint_hash) + ton.VoteComplaint(election_id, complaint_hash) # end define diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 2700de49..0fc09da2 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2238,7 +2238,7 @@ def GetComplaints(self, electionId=None, past=False): item["isPassed"] = (weightRemaining < 0) pseudohash = pubkey + str(electionId) item["pseudohash"] = pseudohash - complaints[pseudohash] = item + complaints[chash] = item #end for # Set buffer @@ -2280,13 +2280,10 @@ def GetComplaintsNumber(self): self.local.add_log("start GetComplaintsNumber function", "debug") result = dict() complaints = self.GetComplaints() - votedComplaints = self.GetVotedComplaints() + voted_complaints = self.GetVotedComplaints(complaints) buff = 0 - for key, item in complaints.items(): - pubkey = item.get("pubkey") - electionId = item.get("electionId") - pseudohash = pubkey + str(electionId) - if pseudohash in votedComplaints: + for chash, item in complaints.values(): + if chash in voted_complaints: continue buff += 1 result["all"] = len(complaints) @@ -2294,15 +2291,6 @@ def GetComplaintsNumber(self): return result #end define - def GetComplaint(self, electionId, complaintHash): - self.local.add_log("start GetComplaint function", "debug") - complaints = self.GetComplaints(electionId) - for key, item in complaints.items(): - if complaintHash == item.get("hash"): - return item - raise Exception("GetComplaint error: complaint not found.") - #end define - def SignProposalVoteRequestWithValidator(self, offerHash, validatorIndex, validatorPubkey_b64, validatorSignature): self.local.add_log("start SignProposalVoteRequestWithValidator function", "debug") fileName = self.tempDir + self.nodeName + "proposal_vote-msg-body.boc" @@ -2391,51 +2379,56 @@ def CheckComplaint(self, file_path: str): return ok #end define - def complaint_is_valid(self, complaint: dict): - self.local.add_log("start complaint_is_valid function", "debug") - - election_id = complaint['electionId'] - voted_complaints = self.GetVotedComplaints(election_id) - if complaint['pseudohash'] in voted_complaints: - self.local.add_log(f"skip checking complaint {complaint['hash_hex']}: " - f"complaint with this pseudohash ({complaint['pseudohash']})" - f" has already been voted", "debug") - return False - - # check that complaint is valid + def get_valid_complaints(self, complaints: dict, election_id: int): + self.local.add_log("start get_valid_complaints function", "debug") config32 = self.GetConfig32() start = config32.get("startWorkTime") - if election_id != start: - self.local.add_log(f"skip checking complaint {complaint['hash_hex']}: " - f"election_id ({election_id}) doesn't match with " - f"start work time ({config32.get('startWorkTime')})", "info") - return False + assert start == election_id, 'provided election_id != election_id from config32' end = config32.get("endWorkTime") - data = self.GetValidatorsLoad(start, end - 60, saveCompFiles=False) + validators_load = self.GetValidatorsLoad(start, end - 60, saveCompFiles=True) + voted_complaints = self.GetVotedComplaints(complaints) + voted_complaints_pseudohashes = [complaint['pseudohash'] for complaint in voted_complaints.values()] + result = {} + for complaint in complaints.values(): + if complaint['pseudohash'] in voted_complaints_pseudohashes or complaint['pseudohash'] in result: + self.local.add_log(f"skip checking complaint {complaint['hash_hex']}: " + f"complaint with this pseudohash ({complaint['pseudohash']})" + f" has already been voted", "debug") + continue + # check that complaint is valid - exists = False - for item in data.values(): - pubkey = item.get("pubkey") - if pubkey is None: + if complaint['electionId'] != start: + self.local.add_log(f"skip checking complaint {complaint['hash_hex']}: " + f"election_id ({election_id}) doesn't match with " + f"start work time ({config32.get('startWorkTime')})", "info") continue - pseudohash = pubkey + str(election_id) - if pseudohash == complaint['pseudohash']: - exists = True - break - if not exists: - self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint info was not found", "info") - return False + exists = False + for item in validators_load.values(): + if 'fileName' not in item: + continue + pubkey = item.get("pubkey") + if pubkey is None: + continue + pseudohash = pubkey + str(election_id) + if pseudohash == complaint['pseudohash']: + exists = True + break - # check complaint fine value - if complaint['suggestedFine'] != 101: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3708 - self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine value is {complaint['suggestedFine']} ton", "info") - return False - if complaint['suggestedFinePart'] != 0: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3709 - self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine part value is {complaint['suggestedFinePart']} ton", "info") - return False + if not exists: + self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint info was not found, probably it's wrong", "info") + continue - return True + # check complaint fine value + if complaint['suggestedFine'] != 101: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3708 + self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine value is {complaint['suggestedFine']} ton", "info") + continue + if complaint['suggestedFinePart'] != 0: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3709 + self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine part value is {complaint['suggestedFinePart']} ton", "info") + continue + + result[complaint['pseudohash']] = complaint + return result def GetOnlineValidators(self): onlineValidators = list() @@ -2449,7 +2442,7 @@ def GetOnlineValidators(self): return onlineValidators #end define - def GetValidatorsLoad(self, start, end, saveCompFiles=False): + def GetValidatorsLoad(self, start, end, saveCompFiles=False) -> dict: # Get buffer bname = f"validatorsLoad{start}{end}" buff = self.GetFunctionBuffer(bname, timeout=60) @@ -2574,6 +2567,7 @@ def CheckValidators(self, start, end): self.local.add_log("start CheckValidators function", "debug") electionId = start complaints = self.GetComplaints(electionId) + valid_complaints = self.get_valid_complaints(complaints, electionId) data = self.GetValidatorsLoad(start, end, saveCompFiles=True) fullElectorAddr = self.GetFullElectorAddr() wallet = self.GetValidatorWallet(mode="vote") @@ -2592,7 +2586,7 @@ def CheckValidators(self, start, end): var2 = item.get("var2") pubkey = item.get("pubkey") pseudohash = pubkey + str(electionId) - if pseudohash in complaints: + if pseudohash in valid_complaints: continue # Create complaint fileName = self.remove_proofs_from_complaint(fileName) @@ -2990,25 +2984,16 @@ def add_save_offer(self, offer): self.local.save() #end define - def GetVotedComplaints(self, election_id: int = None): - complaints = self.GetComplaints(election_id) + def GetVotedComplaints(self, complaints: dict): result = {} validator_index = self.GetValidatorIndex() - for pseudohash, complaint in complaints.items(): - votedValidators = complaint.get("votedValidators") - if validator_index in votedValidators: - result[pseudohash] = complaint + for chash, complaint in complaints.items(): + voted_validators = complaint.get("votedValidators") + if validator_index in voted_validators: + result[chash] = complaint return result #end define - def AddVotedComplaints(self, complaint): - pseudohash = complaint.get("pseudohash") - votedComplaints = self.GetVotedComplaints() - if pseudohash not in votedComplaints: - votedComplaints[pseudohash] = complaint - self.local.save() - #end define - def GetDestinationAddr(self, destination): if self.IsAddrB64(destination): pass From cfd23bd2d041b5d9efb7e94823a86cc3d17202bf Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 8 Mar 2024 12:57:50 +0700 Subject: [PATCH 133/236] bugfix --- mytoncore/functions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 98b8098d..adbaf16a 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -511,8 +511,7 @@ def Complaints(local, ton): valid_complaints = ton.get_valid_complaints(complaints, election_id) for c in valid_complaints.values(): complaint_hash = c.get("hash") - if ton.complaint_is_valid(c): - ton.VoteComplaint(election_id, complaint_hash) + ton.VoteComplaint(election_id, complaint_hash) # end define From 1497b207d063955b7797ebbc2746dcb3fe78100d Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 11 Mar 2024 15:42:18 +0700 Subject: [PATCH 134/236] bugfix --- mytoncore/mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 0fc09da2..7eb93fa4 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2282,7 +2282,7 @@ def GetComplaintsNumber(self): complaints = self.GetComplaints() voted_complaints = self.GetVotedComplaints(complaints) buff = 0 - for chash, item in complaints.values(): + for chash in complaints: if chash in voted_complaints: continue buff += 1 From 5f2355e6be5e7743cbce1837ae6c31107c624c1e Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 11 Mar 2024 21:56:52 +0700 Subject: [PATCH 135/236] fix checking offers --- mytoncore/functions.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index adbaf16a..4e516d26 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -353,7 +353,11 @@ def Offers(local, ton): offer_hash = offer.get("hash") if offer_hash in save_offers: offer_pseudohash = offer.get("pseudohash") - save_offer_pseudohash = save_offers.get(offer_hash) + save_offer = save_offers.get(offer_hash) + if isinstance(save_offer, list): # new version of save offers {"hash": ["pseudohash", param_id]} + save_offer_pseudohash = save_offer[0] + else: # old version of save offers {"hash": "pseudohash"} + save_offer_pseudohash = save_offer if offer_pseudohash == save_offer_pseudohash and offer_pseudohash is not None: ton.VoteOffer(offer_hash) # end define From 591b967411777ba8ccfb097ddc175d4a119a57f7 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:38:27 +0300 Subject: [PATCH 136/236] Create roll_back_001.sh --- mytonctrl/migrations/roll_back_001.sh | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 mytonctrl/migrations/roll_back_001.sh diff --git a/mytonctrl/migrations/roll_back_001.sh b/mytonctrl/migrations/roll_back_001.sh new file mode 100644 index 00000000..ca35c8e7 --- /dev/null +++ b/mytonctrl/migrations/roll_back_001.sh @@ -0,0 +1,16 @@ +pip3 uninstall -y mytonctrl + +cd /usr/src +rm -rf mytonctrl +git clone --recursive https://github.com/ton-blockchain/mytonctrl + +echo "Updating /usr/bin/mytonctrl" +echo "/usr/bin/python3 /usr/src/mytonctrl/mytonctrl.py $@" > /usr/bin/mytonctrl +chmod +x /usr/bin/mytonctrl + +echo "Updating mytoncore service" +sed -i 's\-m mytoncore\/usr/src/mytonctrl/mytoncore.py\g' /etc/systemd/system/mytoncore.service +systemctl daemon-reload +systemctl restart mytoncore + +echo "Done" From 8f30ba1d9d636b569d3f466e21450930d1775601 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 12 Mar 2024 19:05:42 +0700 Subject: [PATCH 137/236] print elections time in UTC --- mytonctrl/mytonctrl.py | 14 +++++++------- mytonctrl/utils.py | 9 +++++++++ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 77a92d5d..7551a716 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -42,7 +42,7 @@ GetBinGitHash, ) from mytonctrl.migrate import run_migrations -from mytonctrl.utils import GetItemFromList +from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime import sys, getopt, os @@ -661,12 +661,12 @@ def PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkT startNextElection = startElection + validatorsElectedFor # timestamp to datetime - rootWorkchainEnabledTime = timestamp2datetime(rootWorkchainEnabledTime_int) - startValidationTime = timestamp2datetime(startValidation) - endValidationTime = timestamp2datetime(endValidation) - startElectionTime = timestamp2datetime(startElection) - endElectionTime = timestamp2datetime(endElection) - startNextElectionTime = timestamp2datetime(startNextElection) + rootWorkchainEnabledTime = timestamp2utcdatetime(rootWorkchainEnabledTime_int) + startValidationTime = timestamp2utcdatetime(startValidation) + endValidationTime = timestamp2utcdatetime(endValidation) + startElectionTime = timestamp2utcdatetime(startElection) + endElectionTime = timestamp2utcdatetime(endElection) + startNextElectionTime = timestamp2utcdatetime(startNextElection) # datetime to color text rootWorkchainEnabledTime_text = local.translate("times_root_workchain_enabled_time").format(bcolors.yellow_text(rootWorkchainEnabledTime)) diff --git a/mytonctrl/utils.py b/mytonctrl/utils.py index 01db5491..12dba3c9 100644 --- a/mytonctrl/utils.py +++ b/mytonctrl/utils.py @@ -1,3 +1,12 @@ +import time + + +def timestamp2utcdatetime(timestamp, format="%d.%m.%Y %H:%M:%S"): + datetime = time.gmtime(timestamp) + result = time.strftime(format, datetime) + ' UTC' + return result + + def GetItemFromList(data, index): try: return data[index] From c1f59b6e8fb0f34fa8cfdabc7d52a0cc26853970 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 13 Mar 2024 15:57:08 +0700 Subject: [PATCH 138/236] add migration to modes --- docs/en/controllers.md | 33 ++++++++++++++++----------------- docs/en/nominator-pool.md | 28 ++++++++++++++-------------- docs/ru/controllers.md | 33 ++++++++++++++++----------------- docs/ru/nominator-pool.md | 30 +++++++++++++++--------------- mytoncore/mytoncore.py | 24 ++++++++++++++++++++---- mytonctrl/mytonctrl.py | 6 +++++- 6 files changed, 86 insertions(+), 68 deletions(-) diff --git a/docs/en/controllers.md b/docs/en/controllers.md index 46b12c8a..66b23c90 100644 --- a/docs/en/controllers.md +++ b/docs/en/controllers.md @@ -25,12 +25,21 @@ ``` Exit installer mode with `Ctrl+D` -7. Set the liquid pool address, which will lend TON for validation: +7. Set liquid-staking mode: + + ```bash + enable_mode liquid-staking + set stake null + ``` + +> (!) If you were previously using nominator pools, do not forget to disable them using the `disable_mode nominator-pool` command. + +8Set the liquid pool address, which will lend TON for validation: ``` set liquid_pool_addr ``` -8. Set the lending parameters that acceptable to you: +9. Set the lending parameters that acceptable to you: ``` set min_loan 41000 set max_loan 43000 @@ -42,18 +51,18 @@ * `43000` is the maximum loan amount we are willing to receive from the liquid pool, * `1.5` 1.5 is the maximum interest rate value for the liquid pool per validation cycle, which we have agreed upon. -9. Display the annual percentage of profit from the liquid pool: +10. Display the annual percentage of profit from the liquid pool: ``` calculate_annual_controller_percentage ``` -10. Create two controllers with a single command: +11. Create two controllers with a single command: ``` new_controllers ``` -11. Enter `controllers_list` to display the controller addresses: +12. Enter `controllers_list` to display the controller addresses: ``` controllers_list @@ -62,7 +71,7 @@ kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 ``` -12. Make a validator deposit in each controller: +13. Make a validator deposit in each controller: ``` @@ -73,17 +82,7 @@ deposit_to_controller kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN 10000 where `10000` TON is the deposit amount. -13. Get approval for the controllers. Each pool may have its own approval issuance policy, check with the operator. - -14. Set controller mode: - - ```bash - set useController true - set stake null - ``` - -> (!) If you were previously using nominator pools, do not forget to disable them using the `set usePool false` command. - +14. Get approval for the controllers. Each pool may have its own approval issuance policy, check with the operator. ## Switching a Regular Validator to Controller Operating Mode diff --git a/docs/en/nominator-pool.md b/docs/en/nominator-pool.md index 4539f2bd..1d0dab10 100644 --- a/docs/en/nominator-pool.md +++ b/docs/en/nominator-pool.md @@ -20,7 +20,14 @@ 4. Use the `aw` command to activate your validator wallet. -5. Create two pools (for even and odd validation rounds): +5. Activate pool mode: + + ```bash + enable_mode nominator-pool + set stake null + ``` + +6. Create two pools (for even and odd validation rounds): ```bash new_pool p1 0 1 1000 300000 @@ -38,7 +45,7 @@ > (!) Use https://tonmon.xyz/ to determine the current minimum validator stake. -6. Type `pools_list` to display pool addresses: +7. Type `pools_list` to display pool addresses: ```bash pools_list @@ -47,7 +54,7 @@ p2 empty 0 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL ``` -7. Send 1 TON to each pool and activate the pools: +8. Send 1 TON to each pool and activate the pools: ```bash mg validator_wallet_001 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT 1 @@ -56,7 +63,7 @@ activate_pool p2 ``` -8. Type `pools_list` to display pools: +9. Type `pools_list` to display pools: ```bash pools_list @@ -65,9 +72,9 @@ p2 active 0.731199806 kf9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV8UO ``` -9. Open each pool via the link "https://tonscan.org/nominator/" and verify pool configurations. +10. Open each pool via the link "https://tonscan.org/nominator/" and verify pool configurations. -10. Proceed with the validator deposit to each pool: +11. Proceed with the validator deposit to each pool: ```bash deposit_to_pool validator_wallet_001 1005 @@ -76,7 +83,7 @@ In these commands, `1005` TON is the deposit amount. Be aware that 1 TON will be deducted by the pool for processing the deposit. -11. Proceed with the nominator deposit to each pool: +12. Proceed with the nominator deposit to each pool: Visit the pool link (from **Step 9**) and click **ADD STAKE**. You can also make a deposit using **mytonctrl**, using the following commands: @@ -92,13 +99,6 @@ > To withdraw a nominator deposit, send a transaction with the comment `w` to the pool address (attach 1 TON to process the transaction). You can also perform this action using **mytonctrl**. -12. Activate pool mode: - - ```bash - set usePool true - set stake null - ``` - 13. Invite nominators to deposit into your pools. The participation in validation will commence automatically. > (!) Ensure that you have at least 200 TON/month in your validator wallet for operation fees. diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md index d3944549..7f985c21 100644 --- a/docs/ru/controllers.md +++ b/docs/ru/controllers.md @@ -26,12 +26,21 @@ ``` Выйдите из режима установщика сочетанием клавиш `Ctrl+D` -7. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: +7. Активируйте режим работы контроллеров: + + ```bash + enable_mode liquid-staking + set stake null + ``` + +> (!) Если до этого вы использовали номинатор-пулы, не забудьте отключить их использование командой `disable_mode nominator-pool`. + +8. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: ``` set liquid_pool_addr ``` -8. Задайте параметры кредитования, которые вам подходят: +9. Задайте параметры кредитования, которые вам подходят: ``` set min_loan 41000 set max_loan 43000 @@ -43,18 +52,18 @@ * `43000` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, * `1.5` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. -9. Отобразите годовой процент прибыли от ликвидного пула: +10. Отобразите годовой процент прибыли от ликвидного пула: ``` calculate_annual_controller_percentage ``` -10. Создайте два контроллера одной командой: +11. Создайте два контроллера одной командой: ``` new_controllers ``` -11. Введите `controllers_list` чтобы отобразить адреса контроллеров: +12. Введите `controllers_list` чтобы отобразить адреса контроллеров: ``` controllers_list @@ -63,7 +72,7 @@ kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 ``` -12. Совершите депозит валидатора в каждый контроллер: +13. Совершите депозит валидатора в каждый контроллер: ``` deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 @@ -72,17 +81,7 @@ где `10000` TON - это сумма депозита. -13. Получите аппрувал контроллеров. У каждого пула может быть своя политика выдачи аппруволов, уточняйте у оператора. - -14. Активируйте режим работы контроллеров: - - ```bash - set useController true - set stake null - ``` - - > (!) Если до этого вы использовали номинатор-пулы, не забудьте отключить их использование командой `set usePool false`. - +14. Получите аппрувал контроллеров. У каждого пула может быть своя политика выдачи аппруволов, уточняйте у оператора. ## Переключение обычного валидатора в режим работы контроллеров diff --git a/docs/ru/nominator-pool.md b/docs/ru/nominator-pool.md index 7d87b2b1..77e88e4c 100644 --- a/docs/ru/nominator-pool.md +++ b/docs/ru/nominator-pool.md @@ -20,7 +20,14 @@ 4. Используйте команду `aw` для активации кошелька валидатора. -5. Создайте два пула (для четного и нечетного раунда проверки): +5. Активируйте режим пула: + + ```bash + enable_mode nominator-pool + set stake null + ``` + +6. Создайте два пула (для четного и нечетного раунда проверки): ``` new_pool p1 0 1 1000 300000 @@ -38,7 +45,7 @@ > (!) Используйте https://tonmon.xyz/, чтобы определить текущую минимальную ставку валидатора. -6. Введите `pools_list` чтобы отобразить адреса пулов: +7. Введите `pools_list` чтобы отобразить адреса пулов: ``` pools_list @@ -47,7 +54,7 @@ p2 empty 0 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL ``` -7. Отправьте по 1 TON в каждый пул и активируйте пулы: +8. Отправьте по 1 TON в каждый пул и активируйте пулы: ``` mg validator_wallet_001 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT 1 @@ -56,7 +63,7 @@ activate_pool p2 ``` -8. Введите `pools_list` чтобы отобразить адреса пулов: +9. Введите `pools_list` чтобы отобразить адреса пулов: ``` pools_list @@ -65,9 +72,9 @@ p2 active 0.731199806 kf9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV8UO ``` -9. Откройте каждый пул по ссылке "https://tonscan.org/nominator/" и проверьте конфигурацию пулов. +10. Откройте каждый пул по ссылке "https://tonscan.org/nominator/" и проверьте конфигурацию пулов. -10. Совершите депозит валидатора в каждый пул: +11. Совершите депозит валидатора в каждый пул: ```bash deposit_to_pool validator_wallet_001 1005 @@ -76,7 +83,7 @@ где `1005` TON - это сумма депозита. Обратите внимание, что пул вычтет 1 TON за обработку депозита. -11. Совершите депозит номинатора в каждый пул: +12. Совершите депозит номинатора в каждый пул: Перейдите по ссылке пула (из **шага 9**) и нажмите **ADD STAKE**. Вы также можете сделать депозит, используя **mytonctrl**, с помощью следующих команд: @@ -92,13 +99,6 @@ > Чтобы снять депозит номинатора, отправьте транзакцию с комментарием `w` на адрес пула (должен быть прикреплен 1 TON для обработки транзакции). Вы также можете сделать это с помощью **mytonctrl**. -12. Активируйте режим пула: - - ```bash - set usePool true - set stake null - ``` - 13. Пригласите номинаторов сделать депозиты в ваши пулы. Участие в валидации начнется автоматически. > (!) Убедитесь, что у вас на кошельке валидатора есть как минимум 200 TON в месяц на операционные расходы. @@ -109,7 +109,7 @@ Если вы создаете пул для многих номинантов, то используйте что-то вроде этого: `new_pool p1 40 40 10000 10000` (максимум 40 номинантов, 40% доли валидатора, минимальная ставка участника 10K TON). -## Переключение обычного валидатора в режим номинантского пула +## Переключение обычного валидатора в режим номинаторского пула 1. Введите `set stake 0`, чтобы отключить участие в выборах. diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 7eb93fa4..636efb87 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3155,10 +3155,28 @@ def SetSettings(self, name, data): self.local.save() #end define + def migrate_to_modes(self): + usePool = self.local.db.get('usePool') + if usePool is not None: + self.enable_mode('nominator-pool') + self.local.db.pop('usePool') + + useController = self.local.db.get('useController') + if useController is not None: + self.enable_mode('liquid-staking') + self.local.db.pop('useController') + self.local.save() + + def rollback_modes(self): + self.local.db['usePool'] = self.get_mode_value('nominator-pool') + self.local.db['useController'] = self.get_mode_value('liquid-staking') + self.local.save() + def get_modes(self): current_modes = self.local.db.get('modes', {}) if 'modes' not in self.local.db: self.local.db['modes'] = current_modes + self.migrate_to_modes() for mode in MODES: if mode not in current_modes: current_modes[mode] = MODES[mode] # assign default mode value @@ -3185,15 +3203,13 @@ def get_mode_value(self, name): return current_modes[name] def using_nominator_pool(self): - return (self.local.db.get("usePool") or # for backward compatibility - self.get_mode_value('nominator-pool')) + return self.get_mode_value('nominator-pool') def using_single_nominator(self): return self.get_mode_value('single-nominator') def using_liquid_staking(self): - return (self.local.db.get("useController") or # for backward compatibility - self.get_mode_value('liquid-staking')) + return self.get_mode_value('liquid-staking') def using_pool(self) -> bool: return self.using_nominator_pool() or self.using_single_nominator() diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 7551a716..176741a0 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -121,7 +121,7 @@ def inject_globals(func): #console.AddItem("ssoc", inject_globals(SignShardOverlayCert), local.translate("ssoc_cmd")) #console.AddItem("isoc", inject_globals(ImportShardOverlayCert), local.translate("isoc_cmd")) - if ton.get_mode_value('validator'): + if ton.using_validator(): from mytonctrl.modules.validator import ValidatorModule module = ValidatorModule(ton, local) module.add_console_commands(console) @@ -1215,6 +1215,10 @@ def SetSettings(ton, args): except: color_print("{red}Bad args. Usage:{endc} set ") return + if name == 'usePool' or name == 'useController': + mode_name = 'nominator-pool' if name == 'usePool' else 'liquid-staking' + color_print("{red}" + f"Error: set {name} ... is deprecated and does not work" + "{endc}" + f"\nInstead, use enable_mode {mode_name}") + return ton.SetSettings(name, value) color_print("SetSettings - {green}OK{endc}") #end define From e8fa8de4ba9dc249fc69335acd55b34c5f7aa9ad Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 13 Mar 2024 16:19:45 +0700 Subject: [PATCH 139/236] move modules to root --- {mytonctrl/modules => modules}/__init__.py | 0 {mytonctrl/modules => modules}/controller.py | 2 +- {mytonctrl/modules => modules}/module.py | 0 {mytonctrl/modules => modules}/nominator_pool.py | 2 +- {mytonctrl/modules => modules}/pool.py | 4 +--- {mytonctrl/modules => modules}/single_pool.py | 2 +- {mytonctrl/modules => modules}/validator.py | 2 +- mytonctrl/mytonctrl.py | 14 ++++++-------- 8 files changed, 11 insertions(+), 15 deletions(-) rename {mytonctrl/modules => modules}/__init__.py (100%) rename {mytonctrl/modules => modules}/controller.py (99%) rename {mytonctrl/modules => modules}/module.py (100%) rename {mytonctrl/modules => modules}/nominator_pool.py (98%) rename {mytonctrl/modules => modules}/pool.py (96%) rename {mytonctrl/modules => modules}/single_pool.py (98%) rename {mytonctrl/modules => modules}/validator.py (96%) diff --git a/mytonctrl/modules/__init__.py b/modules/__init__.py similarity index 100% rename from mytonctrl/modules/__init__.py rename to modules/__init__.py diff --git a/mytonctrl/modules/controller.py b/modules/controller.py similarity index 99% rename from mytonctrl/modules/controller.py rename to modules/controller.py index be859ae4..62d267d6 100644 --- a/mytonctrl/modules/controller.py +++ b/modules/controller.py @@ -5,7 +5,7 @@ from mypylib.mypylib import color_print, print_table from mytonctrl.utils import GetItemFromList -from mytonctrl.modules.module import MtcModule +from modules.module import MtcModule class ControllerModule(MtcModule): diff --git a/mytonctrl/modules/module.py b/modules/module.py similarity index 100% rename from mytonctrl/modules/module.py rename to modules/module.py diff --git a/mytonctrl/modules/nominator_pool.py b/modules/nominator_pool.py similarity index 98% rename from mytonctrl/modules/nominator_pool.py rename to modules/nominator_pool.py index 9a632209..0f3b90f5 100644 --- a/mytonctrl/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -2,7 +2,7 @@ import time from mypylib.mypylib import color_print -from mytonctrl.modules.pool import PoolModule +from modules.pool import PoolModule class NominatorPoolModule(PoolModule): diff --git a/mytonctrl/modules/pool.py b/modules/pool.py similarity index 96% rename from mytonctrl/modules/pool.py rename to modules/pool.py index 68ba6191..a9086900 100644 --- a/mytonctrl/modules/pool.py +++ b/modules/pool.py @@ -1,7 +1,5 @@ -import os - from mypylib.mypylib import color_print, print_table -from mytonctrl.modules.module import MtcModule +from modules.module import MtcModule class PoolModule(MtcModule): diff --git a/mytonctrl/modules/single_pool.py b/modules/single_pool.py similarity index 98% rename from mytonctrl/modules/single_pool.py rename to modules/single_pool.py index 5cd60ee4..5b419f4c 100644 --- a/mytonctrl/modules/single_pool.py +++ b/modules/single_pool.py @@ -3,7 +3,7 @@ import pkg_resources from mypylib.mypylib import color_print -from mytonctrl.modules.pool import PoolModule +from modules.pool import PoolModule class SingleNominatorModule(PoolModule): diff --git a/mytonctrl/modules/validator.py b/modules/validator.py similarity index 96% rename from mytonctrl/modules/validator.py rename to modules/validator.py index 05fc71ae..30f42140 100644 --- a/mytonctrl/modules/validator.py +++ b/modules/validator.py @@ -1,5 +1,5 @@ from mypylib.mypylib import color_print -from mytonctrl.modules.module import MtcModule +from modules.module import MtcModule from mytoncore.functions import Elections diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 176741a0..1e0505c8 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -7,7 +7,6 @@ import pkg_resources import socket -from shutil import copyfile from functools import partial from mypylib.mypylib import ( @@ -35,8 +34,7 @@ from mypyconsole.mypyconsole import MyPyConsole from mytoncore.mytoncore import MyTonCore from mytoncore.functions import ( - Slashing, - Elections, + Slashing, GetMemoryInfo, GetSwapInfo, GetBinGitHash, @@ -122,27 +120,27 @@ def inject_globals(func): #console.AddItem("isoc", inject_globals(ImportShardOverlayCert), local.translate("isoc_cmd")) if ton.using_validator(): - from mytonctrl.modules.validator import ValidatorModule + from modules.validator import ValidatorModule module = ValidatorModule(ton, local) module.add_console_commands(console) if ton.using_pool(): # add basic pool functions (pools_list, delete_pool, import_pool) - from mytonctrl.modules.pool import PoolModule + from modules.pool import PoolModule module = PoolModule(ton, local) module.add_console_commands(console) if ton.using_nominator_pool(): - from mytonctrl.modules.nominator_pool import NominatorPoolModule + from modules.nominator_pool import NominatorPoolModule module = NominatorPoolModule(ton, local) module.add_console_commands(console) if ton.get_mode_value('single-nominator'): - from mytonctrl.modules.single_pool import SingleNominatorModule + from modules.single_pool import SingleNominatorModule module = SingleNominatorModule(ton, local) module.add_console_commands(console) if ton.using_liquid_staking(): - from mytonctrl.modules.controller import ControllerModule + from modules.controller import ControllerModule module = ControllerModule(ton, local) module.add_console_commands(console) From b712acc61671410aa82da437b91851591f7c3d42 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 13 Mar 2024 16:37:31 +0700 Subject: [PATCH 140/236] bugfix --- mytoncore/mytoncore.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 636efb87..3f92d912 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3158,12 +3158,14 @@ def SetSettings(self, name, data): def migrate_to_modes(self): usePool = self.local.db.get('usePool') if usePool is not None: - self.enable_mode('nominator-pool') + if usePool: + self.enable_mode('nominator-pool') self.local.db.pop('usePool') useController = self.local.db.get('useController') if useController is not None: - self.enable_mode('liquid-staking') + if useController: + self.enable_mode('liquid-staking') self.local.db.pop('useController') self.local.save() From 08bd78edecd9e63921489db3195122ed91d961de Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 14 Mar 2024 14:09:56 +0700 Subject: [PATCH 141/236] add rollback --- mytoncore/mytoncore.py | 3 ++- mytonctrl/mytonctrl.py | 15 ++++++++++++++- mytonctrl/resources/translate.json | 5 +++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 3f92d912..aff64285 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3172,13 +3172,14 @@ def migrate_to_modes(self): def rollback_modes(self): self.local.db['usePool'] = self.get_mode_value('nominator-pool') self.local.db['useController'] = self.get_mode_value('liquid-staking') + self.local.db.pop('modes') self.local.save() def get_modes(self): current_modes = self.local.db.get('modes', {}) if 'modes' not in self.local.db: self.local.db['modes'] = current_modes - self.migrate_to_modes() + self.migrate_to_modes() for mode in MODES: if mode not in current_modes: current_modes[mode] = MODES[mode] # assign default mode value diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 1e0505c8..cb72706d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -74,6 +74,7 @@ def inject_globals(func): console.AddItem("disable_mode", inject_globals(disable_mode), local.translate("disable_mode_cmd")) console.AddItem("get", inject_globals(GetSettings), local.translate("get_cmd")) console.AddItem("set", inject_globals(SetSettings), local.translate("set_cmd")) + console.AddItem("rollback", inject_globals(rollback_to_mtc1), local.translate("rollback_cmd")) console.AddItem("seqno", inject_globals(Seqno), local.translate("seqno_cmd")) console.AddItem("getconfig", inject_globals(GetConfig), local.translate("getconfig_cmd")) @@ -325,6 +326,17 @@ def Upgrade(ton, args): color_print(text) #end define +def rollback_to_mtc1(ton, args): + color_print("{red}Warning: this is dangerous, please make sure you've backed up mytoncore's db.{endc}") + a = input("Do you want to continue? [Y/n]") + if a.lower() != 'y': + print('aborted.') + return + ton.rollback_modes() + rollback_script_path = pkg_resources.resource_filename('mytonctrl', 'migrations/roll_back_001.sh') + run_args = ["bash", rollback_script_path] + exit_code = run_as_root(run_args) + def cleanup_validator_db(ton, args): cleanup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/cleanup.sh') run_args = ["bash", cleanup_script_path] @@ -1215,7 +1227,8 @@ def SetSettings(ton, args): return if name == 'usePool' or name == 'useController': mode_name = 'nominator-pool' if name == 'usePool' else 'liquid-staking' - color_print("{red}" + f"Error: set {name} ... is deprecated and does not work" + "{endc}" + f"\nInstead, use enable_mode {mode_name}") + color_print(f"{{red}} Error: set {name} ... is deprecated and does not work {{endc}}." + f"\nInstead, use {{bold}}enable_mode {mode_name}{{endc}}") return ton.SetSettings(name, value) color_print("SetSettings - {green}OK{endc}") diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 3ab39316..ef5e897c 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -29,6 +29,11 @@ "ru": "Выключить режим", "zh_TW": "禁用模式" }, + "rollback_cmd" : { + "en": "Rollback to mytonctrl 1.0", + "ru": "Откатиться к mytonctrl 1.0", + "zh_TW": "回滾到 mytonctrl 1.0" + }, "seqno_cmd": { "en": "Get seqno wallet", "ru": "Получить seqno кошелька", From f78b206617f5c9cb92bc0250d69e1145e033add3 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 14 Mar 2024 15:15:10 +0700 Subject: [PATCH 142/236] check branch exists before update --- mytonctrl/mytonctrl.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index cb72706d..6dd0d0a3 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -272,10 +272,18 @@ def check_git(input_args, default_repo, text): need_repo = local_repo if need_branch is None: need_branch = local_branch - #end if - + check_branch_exists(need_author, need_repo, need_branch) return need_author, need_repo, need_branch -#end define + + +def check_branch_exists(author, repo, branch): + url = f"https://github.com/{author}/{repo}.git" + args = ["git", "ls-remote", "--heads", url, branch] + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + output = process.stdout.decode("utf-8") + if branch not in output: + raise Exception(f"Branch {branch} not found in {url}") + def Update(local, args): repo = "mytonctrl" From 09c90539145ed14117c1fbe8b0252072a8d92983 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 14 Mar 2024 19:18:43 +0700 Subject: [PATCH 143/236] fix rollbacks --- mytonctrl/mytonctrl.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 6dd0d0a3..6628a5a9 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -332,18 +332,26 @@ def Upgrade(ton, args): else: text = "Upgrade - {red}Error{endc}" color_print(text) -#end define -def rollback_to_mtc1(ton, args): + +def rollback_to_mtc1(local, ton, args): color_print("{red}Warning: this is dangerous, please make sure you've backed up mytoncore's db.{endc}") - a = input("Do you want to continue? [Y/n]") + a = input("Do you want to continue? [Y/n]\n") if a.lower() != 'y': print('aborted.') return ton.rollback_modes() + + workdir = local.buffer.my_work_dir + version_file_path = os.path.join(workdir, 'VERSION') + if os.path.exists(version_file_path): + os.remove(version_file_path) + rollback_script_path = pkg_resources.resource_filename('mytonctrl', 'migrations/roll_back_001.sh') run_args = ["bash", rollback_script_path] - exit_code = run_as_root(run_args) + run_as_root(run_args) + local.exit() + def cleanup_validator_db(ton, args): cleanup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/cleanup.sh') From b6dfff0ea3066cfb35dc1ba152141e29dc60e721 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 19 Mar 2024 14:38:41 +0700 Subject: [PATCH 144/236] change GetStake --- mytoncore/mytoncore.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index aff64285..48f8647a 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1316,7 +1316,6 @@ def GetStake(self, account, args=None): # Limit stake to maximum available amount minus 10 (for transaction fees) if stake > account.balance - 10: stake = account.balance - 10 - #end if pool_version = self.GetVersionFromCodeHash(account.codeHash) is_single_nominator = pool_version is not None and 'spool' in pool_version @@ -1331,9 +1330,10 @@ def GetStake(self, account, args=None): self.local.add_log("Wrong stakePercent value. Using default stake.", "warning") elif len(vconfig.validators) == 0: stake = int(account.balance*sp/2) + if stake < config17["minStake"]: # not enough funds to divide them by 2 + stake = int(account.balance*sp) elif len(vconfig.validators) > 0: stake = int(account.balance*sp) - #end if # Check if we have enough coins if stake > config17["maxStake"]: @@ -1348,10 +1348,8 @@ def GetStake(self, account, args=None): text = "Don't have enough coins. stake: {stake}, account balance: {balance}".format(stake=stake, balance=account.balance) # self.local.add_log(text, "error") raise Exception(text) - #end if return stake - #end define def GetMaxFactor(self): # Either use defined maxFactor, or set maximal allowed by config17 From 92eb83b0a505eafe260c67302ae78a08e1dc088c Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 19 Mar 2024 19:37:02 +0700 Subject: [PATCH 145/236] check user before launch --- mytonctrl/mytonctrl.py | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 6628a5a9..0adf7a3c 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -176,13 +176,27 @@ def inject_globals(func): local.db.config.logLevel = "debug" if console.debug else "info" local.db.config.isLocaldbSaving = False local.run() -#end define + + +def check_installer_user(): + args = ["whoami"] + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + username = process.stdout.decode("utf-8").strip() + + args = ["ls", "-lh", "/var/ton-work/keys/"] + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + output = process.stdout.decode("utf-8") + actual_user = output.split('\n')[1].split()[2] + + if username != actual_user: + raise Exception(f'mytonctrl was installed by another user. Probably you need to launch mtc with `{actual_user}` user.') + def PreUp(local, ton): CheckMytonctrlUpdate(local) + check_installer_user() check_vport(local, ton) # CheckTonUpdate() -#end define def Installer(args): # args = ["python3", "/usr/src/mytonctrl/mytoninstaller.py"] @@ -208,7 +222,7 @@ def GetAuthorRepoBranchFromArgs(args): if arg2: data["branch"] = arg2 return data -#end define + def check_vport(local, ton): try: @@ -222,7 +236,6 @@ def check_vport(local, ton): result = client_socket.connect_ex((ip, addr.port)) if result != 0: color_print(local.translate("vport_error")) -#end define def fix_git_config(git_path: str): From f76e3fc0c6b6243c5b07842c341ada409495cd37 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 20 Mar 2024 15:17:58 +0700 Subject: [PATCH 146/236] add sending db stats to telemetry --- mytoncore/functions.py | 51 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 4e516d26..cd659bf0 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*-l import os +import re import sys import psutil import time @@ -419,6 +420,55 @@ def GetValidatorProcessInfo(): # end define +def parse_db_stats(path: str): + with open(path) as f: + lines = f.readlines() + result = {} + for line in lines: + s = line.strip().split(maxsplit=1) + result[s[0]] = {} + items = re.findall(r"(\S+)\s:\s(\S+)", s[1]) + for k, v in items: + result[s[0]][k] = v + return result + + +def get_db_stats(): + result = { + 'rocksdb': { + 'ok': True, + 'message': '', + 'data': {} + }, + 'celldb': { + 'ok': True, + 'message': '', + 'data': {} + }, + } + rocksdb_stats_path = '/var/ton-work/db/db_stats.txt' + celldb_stats_path = '/var/ton-work/db/celldb/db_stats.txt' + if os.path.exists(rocksdb_stats_path): + try: + result['rocksdb']['data'] = parse_db_stats(rocksdb_stats_path) + except Exception as e: + result['rocksdb']['ok'] = False + result['rocksdb']['message'] = f'failed to fetch db stats: {e}' + else: + result['rocksdb']['ok'] = False + result['rocksdb']['message'] = 'db stats file is not exists' + if os.path.exists(celldb_stats_path): + try: + result['celldb']['data'] = parse_db_stats(celldb_stats_path) + except Exception as e: + result['celldb']['ok'] = False + result['celldb']['message'] = f'failed to fetch db stats: {e}' + else: + result['celldb']['ok'] = False + result['celldb']['message'] = 'db stats file is not exists' + return result + + def Telemetry(local, ton): sendTelemetry = local.db.get("sendTelemetry") if sendTelemetry is not True: @@ -442,6 +492,7 @@ def Telemetry(local, ton): data["swap"] = GetSwapInfo() data["uname"] = GetUname() data["vprocess"] = GetValidatorProcessInfo() + data["db"] = get_db_stats() elections = local.try_function(ton.GetElectionEntries) complaints = local.try_function(ton.GetComplaints) From 8951d924e14523ffa9a2dff319a59ba5d5910952 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 20 Mar 2024 22:25:55 +0800 Subject: [PATCH 147/236] return comments --- mytonctrl/mytonctrl.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 0adf7a3c..e087225d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -190,6 +190,7 @@ def check_installer_user(): if username != actual_user: raise Exception(f'mytonctrl was installed by another user. Probably you need to launch mtc with `{actual_user}` user.') +#end define def PreUp(local, ton): @@ -197,6 +198,8 @@ def PreUp(local, ton): check_installer_user() check_vport(local, ton) # CheckTonUpdate() +#end define + def Installer(args): # args = ["python3", "/usr/src/mytonctrl/mytoninstaller.py"] @@ -204,6 +207,7 @@ def Installer(args): subprocess.run(args) #end define + def GetAuthorRepoBranchFromArgs(args): data = dict() arg1 = GetItemFromList(args, 0) @@ -222,6 +226,7 @@ def GetAuthorRepoBranchFromArgs(args): if arg2: data["branch"] = arg2 return data +#end define def check_vport(local, ton): @@ -236,6 +241,7 @@ def check_vport(local, ton): result = client_socket.connect_ex((ip, addr.port)) if result != 0: color_print(local.translate("vport_error")) +#end define def fix_git_config(git_path: str): From e494c60d8c6590d801184c31261e8fca7e674a0a Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 20 Mar 2024 14:36:46 +0700 Subject: [PATCH 148/236] improve pool choosing --- mytoncore/mytoncore.py | 55 +++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index aff64285..157ce850 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1318,8 +1318,7 @@ def GetStake(self, account, args=None): stake = account.balance - 10 #end if - pool_version = self.GetVersionFromCodeHash(account.codeHash) - is_single_nominator = pool_version is not None and 'spool' in pool_version + is_single_nominator = self.is_account_single_nominator(account) if stake is None and usePool and not is_single_nominator: stake = account.balance - 20 @@ -1377,7 +1376,6 @@ def ElectionEntry(self, args=None): addrB64 = wallet.addrB64 if wallet is None: raise Exception("Validator wallet not found") - #end if self.local.add_log("start ElectionEntry function", "debug") # Check if validator is not synchronized @@ -1386,7 +1384,6 @@ def ElectionEntry(self, args=None): if validatorOutOfSync > 60: self.local.add_log("Validator is not synchronized", "error") return - #end if # Get startWorkTime and endWorkTime fullElectorAddr = self.GetFullElectorAddr() @@ -1425,17 +1422,15 @@ def ElectionEntry(self, args=None): if adnl_addr in entries: self.local.add_log("Elections entry already completed", "info") return - #end if if usePool: - pool = self.GetPool(mode="stake") + pool = self.get_pool() addrB64 = pool.addrB64 elif useController: controllerAddr = self.GetController(mode="stake") self.CheckController(controllerAddr) self.CreateLoanRequest(controllerAddr) addrB64 = controllerAddr - #end if # Calculate stake account = self.GetAccount(addrB64) @@ -3547,38 +3542,42 @@ def GetPools(self): pool = self.GetLocalPool(poolName) pools.append(pool) return pools - #end define - def GetPool(self, mode): + def get_pool(self): pools = self.GetPools() for pool in pools: - if mode == "stake" and self.IsPoolReadyToStake(pool.addrB64): - return pool - if mode == "vote" and self.IsPoolReadyToVote(pool.addrB64): + if self.is_pool_ready_to_stake(pool): return pool raise Exception("Validator pool not found or not ready") - #end define - def GetPoolLastSentStakeTime(self, addrB64): - poolData = self.GetPoolData(addrB64) - return poolData["stakeAt"] - #end define + def get_pool_last_sent_stake_time(self, addrB64): + pool_data = self.GetPoolData(addrB64) + return pool_data["stakeAt"] - def IsPoolReadyToStake(self, addrB64): + def is_pool_ready_to_stake(self, pool: Pool): + addr = pool.addrB64 + account = self.GetAccount(addr) + is_single_nominator = self.is_account_single_nominator(account) + if self.using_single_nominator() and not is_single_nominator: + return False + try: # check that account balance is enough for stake + stake = self.GetStake(account) + if not stake: + raise Exception(f'Stake is {stake}') + except Exception as e: + self.local.add_log(f"Failed to get stake for pool {addr}: {e}", "debug") + return False now = get_timestamp() config15 = self.GetConfig15() - lastSentStakeTime = self.GetPoolLastSentStakeTime(addrB64) - stakeFreezeDelay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] - result = lastSentStakeTime + stakeFreezeDelay < now - print(f"{addrB64}: {result}. {lastSentStakeTime}, {stakeFreezeDelay}, {now}") + last_sent_stake_time = self.get_pool_last_sent_stake_time(addr) + stake_freeze_delay = config15["validatorsElectedFor"] + config15["stakeHeldFor"] + result = last_sent_stake_time + stake_freeze_delay < now + print(f"{addr}: {result}. {last_sent_stake_time}, {stake_freeze_delay}, {now}") return result - #end define - def IsPoolReadyToVote(self, addrB64): - vwl = self.GetValidatorsWalletsList() - result = addrB64 in vwl - return result - #end define + def is_account_single_nominator(self, account: Account): + account_version = self.GetVersionFromCodeHash(account.codeHash) + return account_version is not None and 'spool' in account_version def GetPoolData(self, addrB64): self.local.add_log("start GetPoolData function", "debug") From 0a635617ba4af14bb8333f4d76f7d596094b65f2 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 21 Mar 2024 13:58:22 +0800 Subject: [PATCH 149/236] return comments --- mytoncore/mytoncore.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 157ce850..841686b9 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1376,6 +1376,7 @@ def ElectionEntry(self, args=None): addrB64 = wallet.addrB64 if wallet is None: raise Exception("Validator wallet not found") + #end if self.local.add_log("start ElectionEntry function", "debug") # Check if validator is not synchronized @@ -1384,6 +1385,7 @@ def ElectionEntry(self, args=None): if validatorOutOfSync > 60: self.local.add_log("Validator is not synchronized", "error") return + #end if # Get startWorkTime and endWorkTime fullElectorAddr = self.GetFullElectorAddr() @@ -1405,6 +1407,7 @@ def ElectionEntry(self, args=None): if (startWorkTime - now) > self.local.db["participateBeforeEnd"] and \ (now + self.local.db["periods"]["elections"]) < startWorkTime: return + #end if vconfig = self.GetValidatorConfig() @@ -1414,14 +1417,17 @@ def ElectionEntry(self, args=None): if base64.b64decode(a.id) == adnl_addr_bytes: have_adnl = True break + #end for if not have_adnl: raise Exception('ADNL address is not found') + #end if # Check if election entry already completed entries = self.GetElectionEntries() if adnl_addr in entries: self.local.add_log("Elections entry already completed", "info") return + #end if if usePool: pool = self.get_pool() @@ -3542,6 +3548,7 @@ def GetPools(self): pool = self.GetLocalPool(poolName) pools.append(pool) return pools + #end define def get_pool(self): pools = self.GetPools() @@ -3549,10 +3556,12 @@ def get_pool(self): if self.is_pool_ready_to_stake(pool): return pool raise Exception("Validator pool not found or not ready") + #end define def get_pool_last_sent_stake_time(self, addrB64): pool_data = self.GetPoolData(addrB64) return pool_data["stakeAt"] + #end define def is_pool_ready_to_stake(self, pool: Pool): addr = pool.addrB64 @@ -3574,10 +3583,12 @@ def is_pool_ready_to_stake(self, pool: Pool): result = last_sent_stake_time + stake_freeze_delay < now print(f"{addr}: {result}. {last_sent_stake_time}, {stake_freeze_delay}, {now}") return result + #end define def is_account_single_nominator(self, account: Account): account_version = self.GetVersionFromCodeHash(account.codeHash) return account_version is not None and 'spool' in account_version + #end define def GetPoolData(self, addrB64): self.local.add_log("start GetPoolData function", "debug") From 506c4cc0edf2bad5c266d890eb70831ea48f3876 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 21 Mar 2024 14:43:57 +0800 Subject: [PATCH 150/236] change default branch --- mytonctrl/mytonctrl.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index e087225d..4a8c0f92 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -264,7 +264,8 @@ def check_git(input_args, default_repo, text): git_path = f"{src_dir}/{default_repo}" fix_git_config(git_path) default_author = "ton-blockchain" - default_branch = "master" + # default_branch = "master" + default_branch = "mytonctrl2" # Get author, repo, branch local_author, local_repo = get_git_author_and_repo(git_path) From 7acc59ac6b8f466d1587c5dfa2417d281b611f46 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 22 Mar 2024 11:54:00 +0800 Subject: [PATCH 151/236] update db stats parsing --- mytoncore/functions.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index cd659bf0..4abb8a81 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -426,10 +426,15 @@ def parse_db_stats(path: str): result = {} for line in lines: s = line.strip().split(maxsplit=1) - result[s[0]] = {} items = re.findall(r"(\S+)\s:\s(\S+)", s[1]) - for k, v in items: - result[s[0]][k] = v + if len(items) == 1: + item = items[0] + if float(item[1]) > 0: + result[s[0]] = float(item[1]) + else: + if any(float(v) > 0 for k, v in items): + result[s[0]] = {} + result[s[0]] = {k: float(v) for k, v in items} return result From 3c3c80577ad580c725e7813f5786e338d75c6758 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 22 Mar 2024 11:58:00 +0800 Subject: [PATCH 152/236] improves --- mytoncore/functions.py | 30 ++++++++------------------- mytoncore/utils.py | 46 ++++++++++++++++++++++++++++++------------ 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 4abb8a81..ffb9a3ef 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*-l import os -import re import sys import psutil import time @@ -9,8 +8,8 @@ import requests import subprocess -from mytoncore.mytoncore import MyTonCore, Dec2HexAddr -from mytoncore.tonblocksscanner import TonBlocksScanner +from mytoncore.mytoncore import MyTonCore +from mytoncore.utils import parse_db_stats from mypylib.mypylib import ( b2mb, get_timestamp, @@ -420,24 +419,6 @@ def GetValidatorProcessInfo(): # end define -def parse_db_stats(path: str): - with open(path) as f: - lines = f.readlines() - result = {} - for line in lines: - s = line.strip().split(maxsplit=1) - items = re.findall(r"(\S+)\s:\s(\S+)", s[1]) - if len(items) == 1: - item = items[0] - if float(item[1]) > 0: - result[s[0]] = float(item[1]) - else: - if any(float(v) > 0 for k, v in items): - result[s[0]] = {} - result[s[0]] = {k: float(v) for k, v in items} - return result - - def get_db_stats(): result = { 'rocksdb': { @@ -462,6 +443,8 @@ def get_db_stats(): else: result['rocksdb']['ok'] = False result['rocksdb']['message'] = 'db stats file is not exists' + # end if + if os.path.exists(celldb_stats_path): try: result['celldb']['data'] = parse_db_stats(celldb_stats_path) @@ -471,7 +454,10 @@ def get_db_stats(): else: result['celldb']['ok'] = False result['celldb']['message'] = 'db stats file is not exists' + # end if + return result +# end define def Telemetry(local, ton): @@ -497,7 +483,7 @@ def Telemetry(local, ton): data["swap"] = GetSwapInfo() data["uname"] = GetUname() data["vprocess"] = GetValidatorProcessInfo() - data["db"] = get_db_stats() + data["dbStats"] = get_db_stats() elections = local.try_function(ton.GetElectionEntries) complaints = local.try_function(ton.GetComplaints) diff --git a/mytoncore/utils.py b/mytoncore/utils.py index 9743b0fc..0a8bdc91 100644 --- a/mytoncore/utils.py +++ b/mytoncore/utils.py @@ -1,5 +1,6 @@ import base64 import json +import re def str2b64(s): @@ -49,19 +50,19 @@ def b642hex(input): def xhex2hex(x): - try: - b = x[1:] - h = b.lower() - return h - except: - return None + 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 + b = bytes.fromhex(h) + b64 = base64.b64encode(b) + s = b64.decode("utf-8") + return s #end define @@ -73,7 +74,26 @@ def str2bool(str): def ng2g(ng): - if ng is None: - return - return int(ng)/10**9 + if ng is None: + return + return int(ng)/10**9 #end define + + +def parse_db_stats(path: str): + with open(path) as f: + lines = f.readlines() + result = {} + for line in lines: + s = line.strip().split(maxsplit=1) + items = re.findall(r"(\S+)\s:\s(\S+)", s[1]) + if len(items) == 1: + item = items[0] + if float(item[1]) > 0: + result[s[0]] = float(item[1]) + else: + if any(float(v) > 0 for k, v in items): + result[s[0]] = {} + result[s[0]] = {k: float(v) for k, v in items} + return result +# end define From c651f6eb43e68bfdbd2c1e5c6a539efeba588f21 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 22 Mar 2024 20:39:59 +0800 Subject: [PATCH 153/236] add download pool scripts for single-nom, import-pool; move CreatePool to modules --- modules/nominator_pool.py | 33 ++++++++++++++++++++++++++++++++- modules/pool.py | 18 +++++++++++++++++- modules/single_pool.py | 2 ++ mytoncore/mytoncore.py | 38 -------------------------------------- 4 files changed, 51 insertions(+), 40 deletions(-) diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index 0f3b90f5..dc2eec53 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -7,6 +7,37 @@ class NominatorPoolModule(PoolModule): + def do_create_pool(self, pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, + min_nominator_stake): + self.ton.local.add_log("start CreatePool function", "debug") + validator_reward_share = int(validator_reward_share_percent * 100) + + self.check_download_pool_contract_scripts() + + file_path = self.ton.poolsDir + pool_name + if os.path.isfile(file_path + ".addr"): + self.ton.local.add_log("CreatePool warning: Pool already exists: " + file_path, "warning") + return + # end if + + fift_script = self.ton.contractsDir + "nominator-pool/func/new-pool.fif" + wallet = self.ton.GetValidatorWallet() + args = [fift_script, wallet.addrB64, validator_reward_share, max_nominators_count, min_validator_stake, + min_nominator_stake, file_path] + result = self.ton.fift.Run(args) + if "Saved pool" not in result: + raise Exception("CreatePool error: " + result) + # end if + + pools = self.ton.GetPools() + new_pool = self.ton.GetLocalPool(pool_name) + for pool in pools: + if pool.name != new_pool.name and pool.addrB64 == new_pool.addrB64: + new_pool.Delete() + raise Exception("CreatePool error: Pool with the same parameters already exists.") + # end for + # end define + def new_pool(self, args): try: pool_name = args[0] @@ -17,7 +48,7 @@ def new_pool(self, args): except: color_print("{red}Bad args. Usage:{endc} new_pool ") return - self.ton.CreatePool(pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, min_nominator_stake) + self.do_create_pool(pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, min_nominator_stake) color_print("NewPool - {green}OK{endc}") def do_activate_pool(self, pool, ex=True): diff --git a/modules/pool.py b/modules/pool.py index a9086900..e5d90735 100644 --- a/modules/pool.py +++ b/modules/pool.py @@ -1,3 +1,5 @@ +import os + from mypylib.mypylib import color_print, print_table from modules.module import MtcModule @@ -28,6 +30,15 @@ def delete_pool(self, args): pool = self.ton.GetLocalPool(pool_name) pool.Delete() color_print("DeletePool - {green}OK{endc}") + # end define + + def do_import_pool(self, pool_name, addr_b64): + self.check_download_pool_contract_scripts() + addr_bytes = self.ton.addr_b64_to_bytes(addr_b64) + pool_path = self.ton.poolsDir + pool_name + with open(pool_path + ".addr", 'wb') as file: + file.write(addr_bytes) + # end define def import_pool(self, args): try: @@ -36,9 +47,14 @@ def import_pool(self, args): except: color_print("{red}Bad args. Usage:{endc} import_pool ") return - self.ton.import_pool(pool_name, pool_addr) + self.do_import_pool(pool_name, pool_addr) color_print("import_pool - {green}OK{endc}") + def check_download_pool_contract_scripts(self): + contract_path = self.ton.contractsDir + "nominator-pool/" + if not os.path.isdir(contract_path): + self.ton.DownloadContract("https://github.com/ton-blockchain/nominator-pool") + def add_console_commands(self, console): console.AddItem("pools_list", self.print_pools_list, self.local.translate("pools_list_cmd")) console.AddItem("delete_pool", self.delete_pool, self.local.translate("delete_pool_cmd")) diff --git a/modules/single_pool.py b/modules/single_pool.py index 5b419f4c..490ebbc6 100644 --- a/modules/single_pool.py +++ b/modules/single_pool.py @@ -11,6 +11,8 @@ class SingleNominatorModule(PoolModule): def do_create_single_pool(self, pool_name, owner_address): self.ton.local.add_log("start create_single_pool function", "debug") + self.check_download_pool_contract_scripts() + file_path = self.ton.poolsDir + pool_name if os.path.isfile(file_path + ".addr"): self.ton.local.add_log("create_single_pool warning: Pool already exists: " + file_path, "warning") diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 53b2e5a9..ee5447f7 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1733,13 +1733,6 @@ def ExportWallet(self, walletName): return wallet.addrB64, key #end define - def import_pool(self, pool_name, addr_b64): - addr_bytes = self.addr_b64_to_bytes(addr_b64) - pool_path = self.poolsDir + pool_name - with open(pool_path + ".addr", 'wb') as file: - file.write(addr_bytes) - #end define - def GetWalletsNameList(self): self.local.add_log("start GetWalletsNameList function", "debug") walletsNameList = list() @@ -3396,37 +3389,6 @@ def DownloadContract(self, url, branch=None): #end if #end define - def CreatePool(self, poolName, validatorRewardSharePercent, maxNominatorsCount, minValidatorStake, minNominatorStake): - self.local.add_log("start CreatePool function", "debug") - validatorRewardShare = int(validatorRewardSharePercent * 100) - contractPath = self.contractsDir + "nominator-pool/" - if not os.path.isdir(contractPath): - self.DownloadContract("https://github.com/ton-blockchain/nominator-pool") - #end if - - filePath = self.poolsDir + poolName - if os.path.isfile(filePath + ".addr"): - self.local.add_log("CreatePool warning: Pool already exists: " + filePath, "warning") - return - #end if - - fiftScript = self.contractsDir + "nominator-pool/func/new-pool.fif" - wallet = self.GetValidatorWallet() - args = [fiftScript, wallet.addrB64, validatorRewardShare, maxNominatorsCount, minValidatorStake, minNominatorStake, filePath] - result = self.fift.Run(args) - if "Saved pool" not in result: - raise Exception("CreatePool error: " + result) - #end if - - pools = self.GetPools() - newPool = self.GetLocalPool(poolName) - for pool in pools: - if pool.name != newPool.name and pool.addrB64 == newPool.addrB64: - newPool.Delete() - raise Exception("CreatePool error: Pool with the same parameters already exists.") - #end for - #end define - def WithdrawFromPoolProcess(self, poolAddr, amount): self.local.add_log("start WithdrawFromPoolProcess function", "debug") wallet = self.GetValidatorWallet() From 597dcba308f22ef06aa2933cb09327636a45045d Mon Sep 17 00:00:00 2001 From: yungwine Date: Sun, 24 Mar 2024 21:03:02 +0800 Subject: [PATCH 154/236] add descriptions to modules --- modules/controller.py | 2 ++ modules/module.py | 2 ++ modules/nominator_pool.py | 2 ++ modules/pool.py | 2 ++ modules/single_pool.py | 2 ++ modules/validator.py | 3 +++ 6 files changed, 13 insertions(+) diff --git a/modules/controller.py b/modules/controller.py index 62d267d6..0d9b5e25 100644 --- a/modules/controller.py +++ b/modules/controller.py @@ -10,6 +10,8 @@ class ControllerModule(MtcModule): + description = 'Liquid staking controllers.' + def do_create_controllers(self): new_controllers = self.ton.GetControllers() old_controllers = self.ton.local.db.get("using_controllers", list()) diff --git a/modules/module.py b/modules/module.py index 6ace8e49..f9602899 100644 --- a/modules/module.py +++ b/modules/module.py @@ -4,6 +4,8 @@ class MtcModule(ABC): + description = '' + def __init__(self, ton, local, *args, **kwargs): self.ton: MyTonCore = ton self.local = local diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index dc2eec53..8ae08e5e 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -7,6 +7,8 @@ class NominatorPoolModule(PoolModule): + description = 'Standard nominator pools.' + def do_create_pool(self, pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, min_nominator_stake): self.ton.local.add_log("start CreatePool function", "debug") diff --git a/modules/pool.py b/modules/pool.py index e5d90735..24ebb5d3 100644 --- a/modules/pool.py +++ b/modules/pool.py @@ -6,6 +6,8 @@ class PoolModule(MtcModule): + description = 'Basic pools functions.' + def print_pools_list(self, args): table = list() table += [["Name", "Status", "Balance", "Version", "Address"]] diff --git a/modules/single_pool.py b/modules/single_pool.py index 490ebbc6..e989378d 100644 --- a/modules/single_pool.py +++ b/modules/single_pool.py @@ -8,6 +8,8 @@ class SingleNominatorModule(PoolModule): + description = 'Orbs\'s single nominator pools.' + def do_create_single_pool(self, pool_name, owner_address): self.ton.local.add_log("start create_single_pool function", "debug") diff --git a/modules/validator.py b/modules/validator.py index 30f42140..639daa3f 100644 --- a/modules/validator.py +++ b/modules/validator.py @@ -6,6 +6,9 @@ class ValidatorModule(MtcModule): + description = ('Validator functions. Activates participating in elections and staking. ' + 'If pools and l/s modes are disabled stakes from validator wallet.') + def vote_offer(self, args): if len(args) == 0: color_print("{red}Bad args. Usage:{endc} vo ") From 86a8c700a2b129bcc41c9876359b9263f4481964 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 25 Mar 2024 12:58:35 +0800 Subject: [PATCH 155/236] add default values directly to modules --- modules/__init__.py | 20 ++++++++++++++++++++ modules/controller.py | 1 + modules/module.py | 5 +++-- modules/nominator_pool.py | 1 + modules/pool.py | 1 + modules/single_pool.py | 1 + modules/validator.py | 2 ++ mytoncore/modes.py | 6 ------ mytoncore/mytoncore.py | 8 ++++---- mytonctrl/mytonctrl.py | 15 ++++++++++----- 10 files changed, 43 insertions(+), 17 deletions(-) delete mode 100644 mytoncore/modes.py diff --git a/modules/__init__.py b/modules/__init__.py index e69de29b..5fe73d82 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -0,0 +1,20 @@ +import typing + +from .module import MtcModule +from .pool import PoolModule +from .nominator_pool import NominatorPoolModule +from .single_pool import SingleNominatorModule +from .validator import ValidatorModule +from .controller import ControllerModule + + +MODES = { + 'validator': ValidatorModule, + 'nominator-pool': NominatorPoolModule, + 'single-nominator': SingleNominatorModule, + 'liquid-staking': ControllerModule, +} + + +def get_mode(mode_name: str) -> typing.Optional[MtcModule]: + return MODES.get(mode_name) diff --git a/modules/controller.py b/modules/controller.py index 0d9b5e25..b9fa78ca 100644 --- a/modules/controller.py +++ b/modules/controller.py @@ -11,6 +11,7 @@ class ControllerModule(MtcModule): description = 'Liquid staking controllers.' + default_value = False def do_create_controllers(self): new_controllers = self.ton.GetControllers() diff --git a/modules/module.py b/modules/module.py index f9602899..b1ce709a 100644 --- a/modules/module.py +++ b/modules/module.py @@ -1,12 +1,13 @@ from abc import ABC, abstractmethod -from mytoncore.mytoncore import MyTonCore class MtcModule(ABC): - description = '' + description = '' # module text description + default_value = True # is module enabled by default def __init__(self, ton, local, *args, **kwargs): + from mytoncore.mytoncore import MyTonCore self.ton: MyTonCore = ton self.local = local diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index 8ae08e5e..ad72a94c 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -8,6 +8,7 @@ class NominatorPoolModule(PoolModule): description = 'Standard nominator pools.' + default_value = False def do_create_pool(self, pool_name, validator_reward_share_percent, max_nominators_count, min_validator_stake, min_nominator_stake): diff --git a/modules/pool.py b/modules/pool.py index 24ebb5d3..16b481c5 100644 --- a/modules/pool.py +++ b/modules/pool.py @@ -7,6 +7,7 @@ class PoolModule(MtcModule): description = 'Basic pools functions.' + default_value = False def print_pools_list(self, args): table = list() diff --git a/modules/single_pool.py b/modules/single_pool.py index e989378d..748cc4fd 100644 --- a/modules/single_pool.py +++ b/modules/single_pool.py @@ -9,6 +9,7 @@ class SingleNominatorModule(PoolModule): description = 'Orbs\'s single nominator pools.' + default_value = False def do_create_single_pool(self, pool_name, owner_address): self.ton.local.add_log("start create_single_pool function", "debug") diff --git a/modules/validator.py b/modules/validator.py index 639daa3f..ebceb771 100644 --- a/modules/validator.py +++ b/modules/validator.py @@ -9,6 +9,8 @@ class ValidatorModule(MtcModule): description = ('Validator functions. Activates participating in elections and staking. ' 'If pools and l/s modes are disabled stakes from validator wallet.') + default_value = True + def vote_offer(self, args): if len(args) == 0: color_print("{red}Bad args. Usage:{endc} vo ") diff --git a/mytoncore/modes.py b/mytoncore/modes.py deleted file mode 100644 index d9d76382..00000000 --- a/mytoncore/modes.py +++ /dev/null @@ -1,6 +0,0 @@ -MODES = { # mode_name : is_enabled_by_default - 'validator': True, - 'nominator-pool': False, - 'single-nominator': False, - 'liquid-staking': False, -} \ No newline at end of file diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index ee5447f7..ca350a5f 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -11,7 +11,7 @@ import requests from fastcrc import crc16 -from mytoncore.modes import MODES +from modules import MODES from mytoncore.utils import xhex2hex, ng2g from mytoncore.liteclient import LiteClient from mytoncore.validator_console import ValidatorConsole @@ -3172,9 +3172,9 @@ def get_modes(self): if 'modes' not in self.local.db: self.local.db['modes'] = current_modes self.migrate_to_modes() - for mode in MODES: - if mode not in current_modes: - current_modes[mode] = MODES[mode] # assign default mode value + for name, mode in MODES.items(): + if name not in current_modes: + current_modes[name] = mode.default_value # assign default mode value return current_modes def enable_mode(self, name): diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 4a8c0f92..3477c0f1 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -424,13 +424,18 @@ def sl(ton, args): Slashing(ton.local, ton) #end define + def mode_status(ton, args): + from modules import get_mode modes = ton.get_modes() - text = "########## {bold}Modes{endc} ########## \n" - for mode in modes: - status = '{green}enabled{endc}' if modes[mode] else '{red}disabled{endc}' - text += f"{mode}: {status}\n" - color_print(text) + table = [["Name", "Status", "Description"]] + for mode_name in modes: + mode = get_mode(mode_name) + status = color_text('{green}enabled{endc}' if modes[mode_name] else '{red}disabled{endc}') + table.append([mode_name, status, mode.description]) + print_table(table) +#end define + def PrintStatus(local, ton, args): opt = None From 6f1b686029dca4cf25a9191d1925932b0f49b0ba Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 26 Mar 2024 20:50:15 +0800 Subject: [PATCH 156/236] update installer status --- mytoninstaller/mytoninstaller.py | 27 ++++++++++------- mytoninstaller/node_args.py | 51 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 mytoninstaller/node_args.py diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index ee542a6f..9c03580b 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -11,6 +11,7 @@ from mypyconsole.mypyconsole import MyPyConsole from mytoninstaller.config import GetLiteServerConfig, get_ls_proxy_config +from mytoninstaller.node_args import get_node_args from mytoninstaller.utils import GetInitBlock from mytoncore.utils import dict2b64, str2bool, b642dict @@ -111,16 +112,22 @@ def Status(local, args): 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) + statuses = { + 'Full node status': os.path.isfile(local.buffer.vconfig_path), + 'Mytoncore status': os.path.isfile(local.buffer.mconfig_path), + 'V.console status': os.path.isfile(server_key) or os.path.isfile(client_key), + 'Liteserver status': os.path.isfile(liteserver_pubkey) + } + + color_print("{cyan}===[ Services status ]==={endc}") + for item in statuses.items(): + status = '{green}enabled{endc}' if item[1] else '{red}disabled{endc}' + color_print(f"{item[0]}: {status}") + + node_args = get_node_args() + color_print("{cyan}===[ Node arguments ]==={endc}") + for key, value in node_args.items(): + print(f"{key}: {value}") #end define diff --git a/mytoninstaller/node_args.py b/mytoninstaller/node_args.py new file mode 100644 index 00000000..97426eea --- /dev/null +++ b/mytoninstaller/node_args.py @@ -0,0 +1,51 @@ + + +def get_validator_service(): + path = '/etc/systemd/system/validator.service' + with open(path, 'r') as f: + return f.read() + + +def get_node_start_command(): + service = get_validator_service() + for line in service.split('\n'): + if 'ExecStart' in line: + return line.split('=')[1].strip() + + +def get_node_args(command: str = None): + if command is None: + command = get_node_start_command() + result = {} + key = '' + for c in command.split(' ')[1:]: + if c.startswith('--') or c.startswith('-'): + if key: + result[key] = '' + key = c + elif key: + result[key] = c + key = '' + return result + + +def set_node_arg(arg_name: str, arg_value: str = ''): + """ + :param arg_name: + :param arg_value: arg value. if None, remove the arg; if empty string, argument is set without value + :return: + """ + assert arg_name.startswith('-'), 'arg_name must start with "-" or "--"' + service = get_validator_service() + command = get_node_start_command() + if command is None: + raise Exception('Cannot find node start command in service file') + args = get_node_args(command) + if arg_value is None: + args.pop(arg_name, None) + else: + args[arg_name] = arg_value + new_command = command.split(' ')[0] + ' ' + ' '.join([f'{k} {v}' for k, v in args.items()]) + new_service = service.replace(command, new_command) + with open('/etc/systemd/system/validator.service', 'w') as f: + f.write(new_service) From 3a0b71f4470fb78b53fa62edc2ccf989fa8fbb80 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 27 Mar 2024 11:33:49 +0800 Subject: [PATCH 157/236] add set_node_argument --- mytoninstaller/mytoninstaller.py | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 9c03580b..466861b2 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -11,7 +11,7 @@ from mypyconsole.mypyconsole import MyPyConsole from mytoninstaller.config import GetLiteServerConfig, get_ls_proxy_config -from mytoninstaller.node_args import get_node_args +from mytoninstaller.node_args import get_node_args, set_node_arg from mytoninstaller.utils import GetInitBlock from mytoncore.utils import dict2b64, str2bool, b642dict @@ -63,6 +63,7 @@ def inject_globals(func): console.name = "MyTonInstaller" console.color = console.RED console.AddItem("status", inject_globals(Status), "Print TON component status") + console.AddItem("set_node_argument", inject_globals(set_node_argument), "Set node argument") console.AddItem("enable", inject_globals(Enable), "Enable some function") console.AddItem("update", inject_globals(Enable), "Update some function: 'JR' - jsonrpc. Example: 'update JR'") console.AddItem("plsc", inject_globals(PrintLiteServerConfig), "Print lite-server config") @@ -131,6 +132,34 @@ def Status(local, args): #end define +def restart_node(): + exit_code = run_as_root(["systemctl", "daemon-reload"]) + if not exit_code: + raise Exception(f"`systemctl daemon-reload` failed with exit code {exit_code}") + exit_code = run_as_root(["systemctl", "restart", "validator"]) + if not exit_code: + raise Exception(f"`systemctl restart validator` failed with exit code {exit_code}") +#end define + + +def set_node_argument(local, args): + if len(args) < 1: + color_print("{red}Bad args. Usage:{endc} set_node_argument [arg-value] [-d (to delete)]") + return + arg_name = args[0] + if len(args) == 1: + set_node_arg(arg_name) + else: + arg_value = args[1] + if arg_value == "-d": + set_node_arg(arg_name, None) + else: + set_node_arg(arg_name, arg_value) + restart_node() + color_print("set_node_argument - {green}OK{endc}") +#end define + + def Enable(local, args): try: name = args[0] From e8345490818bc28cc56753a99c6d2d81a0e81197 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 27 Mar 2024 18:20:44 +0800 Subject: [PATCH 158/236] bugfix --- mytoninstaller/mytoninstaller.py | 4 ++-- mytoninstaller/node_args.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 466861b2..2f9a7577 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -134,10 +134,10 @@ def Status(local, args): def restart_node(): exit_code = run_as_root(["systemctl", "daemon-reload"]) - if not exit_code: + if exit_code: raise Exception(f"`systemctl daemon-reload` failed with exit code {exit_code}") exit_code = run_as_root(["systemctl", "restart", "validator"]) - if not exit_code: + if exit_code: raise Exception(f"`systemctl restart validator` failed with exit code {exit_code}") #end define diff --git a/mytoninstaller/node_args.py b/mytoninstaller/node_args.py index 97426eea..96abbcfb 100644 --- a/mytoninstaller/node_args.py +++ b/mytoninstaller/node_args.py @@ -26,6 +26,8 @@ def get_node_args(command: str = None): elif key: result[key] = c key = '' + if key: + result[key] = '' return result From 74147cb9efafd0567f6fdfd39d2dd18ba5c45278 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 27 Mar 2024 15:52:01 +0300 Subject: [PATCH 159/236] add ton_storage_provider --- docs/ru/ton-storage-provider.md | 32 ++++ mytoncore/functions.py | 23 ++- mytoncore/mytoncore.py | 57 +++++-- mytonctrl/mytonctrl.py | 19 +++ mytoninstaller/config.py | 8 + mytoninstaller/mytoninstaller.py | 8 +- mytoninstaller/scripts/ls_proxy_installer.sh | 61 +++---- .../scripts/ton_storage_installer.sh | 70 ++++++++ .../scripts/ton_storage_provider_installer.sh | 70 ++++++++ mytoninstaller/scripts/utils.sh | 54 +++++++ mytoninstaller/settings.py | 151 +++++++++++++++++- 11 files changed, 491 insertions(+), 62 deletions(-) create mode 100644 docs/ru/ton-storage-provider.md create mode 100644 mytoninstaller/scripts/ton_storage_installer.sh create mode 100644 mytoninstaller/scripts/ton_storage_provider_installer.sh create mode 100644 mytoninstaller/scripts/utils.sh diff --git a/docs/ru/ton-storage-provider.md b/docs/ru/ton-storage-provider.md new file mode 100644 index 00000000..3500b5b3 --- /dev/null +++ b/docs/ru/ton-storage-provider.md @@ -0,0 +1,32 @@ +# TON storage provider + +MyTonCtrl поддерживает установку дополнительных компонентов таких как `TON storage` и `TON storage provider`. С их помощью вы можете хранить пользовательские файлы у себя на сервере и получать за это вознаграждение. + +## Установка дополнительных компонентов + +Войдите в MyTonCtrl +``` +mytonctrl +``` + +Затем войдите в режим установщика +``` +installer +``` + +После включите нужный функционал TON storage provider: +``` +enable TSP +``` + +## Активация контракта провайдера + +В ходе установки дополнительных компонетов был создан специальный кошелек провайдера `provider_wallet_001` откуда будут отправляться доказательства и куда будет приходить награда. +Для его работы сначала нужно пополнить этот кошелек на 1 монету и активировать его командой внутри MyTonCtrl, в ходе которого он так же зарегистрируется в списке провайдеров: +``` +activate_ton_storage_provider +``` + +## Панель управления TON storage provider + +TODO diff --git a/mytoncore/functions.py b/mytoncore/functions.py index ffb9a3ef..4ce34ef3 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -5,11 +5,13 @@ import psutil import time import json +import base64 import requests import subprocess from mytoncore.mytoncore import MyTonCore from mytoncore.utils import parse_db_stats +from mytoninstaller.config import GetConfig from mypylib.mypylib import ( b2mb, get_timestamp, @@ -26,8 +28,8 @@ def Init(local): # Event reaction if ("-e" in sys.argv): x = sys.argv.index("-e") - eventName = sys.argv[x+1] - Event(local, eventName) + event_name = sys.argv[x+1] + Event(local, event_name) # end if local.run() @@ -46,11 +48,13 @@ def Init(local): # end define -def Event(local, eventName): - if eventName == "enableVC": +def Event(local, event_name): + if event_name == "enableVC": EnableVcEvent(local) - elif eventName == "validator down": + elif event_name == "validator down": ValidatorDownEvent(local) + elif event_name == "enable_ton_storage_provider": + enable_ton_storage_provider_event(local) local.exit() # end define @@ -78,6 +82,15 @@ def ValidatorDownEvent(local): # end define +def enable_ton_storage_provider_event(local): + config_path = local.db.ton_storage.provider.config_path + config = GetConfig(path=config_path) + key_bytes = base64.b64decode(config.ProviderKey) + ton = MyTonCore(local) + ton.import_wallet_with_version(key_bytes[:32], version="v3r2", wallet_name="provider_wallet_001") +#end define + + def Elections(local, ton): use_pool = ton.using_pool() use_liquid_staking = ton.using_liquid_staking() diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index ee5447f7..6498a191 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1656,17 +1656,11 @@ def CreateWallet(self, name, workchain=0, version="v1", **kwargs): if os.path.isfile(walletPath + ".pk") and "v3" not in version: self.local.add_log("CreateWallet error: Wallet already exists: " + name, "warning") else: - if "v1" in version: - fiftScript = "new-wallet.fif" - args = [fiftScript, workchain, walletPath] - if "v2" in version: - fiftScript = "new-wallet-v2.fif" - args = [fiftScript, workchain, walletPath] - if "v3" in version: - fiftScript = "new-wallet-v3.fif" - args = [fiftScript, workchain, subwallet, walletPath] - result = self.fift.Run(args) + fift_args = self.get_new_wallet_fift_args(version, workchain=workchain, + wallet_path=wallet_path, subwallet=subwallet) + result = self.fift.Run(fift_args) if "Creating new" not in result: + print(result) raise Exception("CreateWallet error") #end if wallet = self.GetLocalWallet(name, version) @@ -1717,6 +1711,49 @@ def ImportWallet(self, addr_b64, key): return wallet_name #end define + def import_wallet_with_version(self, key, version, **kwargs): + wallet_name = kwargs.get("wallet_name") + workchain = kwargs.get("workchain", 0) + subwallet_default = 698983191 + workchain # 0x29A9A317 + workchain + subwallet = kwargs.get("subwallet", subwallet_default) + if type(key) == bytes: + pk_bytes = key + else: + pk_bytes = base64.b64decode(key) + if wallet_name == None: + wallet_name = self.GenerateWalletName() + wallet_path = self.walletsDir + wallet_name + with open(wallet_path + ".pk", 'wb') as file: + file.write(pk_bytes) + fift_args = self.get_new_wallet_fift_args(version, workchain=workchain, + wallet_path=wallet_path, subwallet=subwallet) + result = self.fift.Run(fift_args) + if "Creating new" not in result: + print(result) + raise Exception("import_wallet_with_version error") + wallet = self.GetLocalWallet(wallet_name, version) + self.SetWalletVersion(wallet.addrB64, version) + return wallet + #end define + + def get_new_wallet_fift_args(self, version, **kwargs): + workchain = kwargs.get("workchain") + wallet_path = kwargs.get("wallet_path") + subwallet = kwargs.get("subwallet") + if "v1" in version: + fift_script = "new-wallet.fif" + args = [fift_script, workchain, wallet_path] + elif "v2" in version: + fift_script = "new-wallet-v2.fif" + args = [fift_script, workchain, wallet_path] + elif "v3" in version: + fift_script = "new-wallet-v3.fif" + args = [fift_script, workchain, subwallet, wallet_path] + else: + raise Exception(f"get_wallet_fift error: fift script for `{version}` not found") + return args + #end define + def addr_b64_to_bytes(self, addr_b64): workchain, addr, bounceable = self.ParseAddrB64(addr_b64) workchain_bytes = int.to_bytes(workchain, 4, "big", signed=True) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 4a8c0f92..9c407dd7 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -147,6 +147,7 @@ def inject_globals(func): console.AddItem("cleanup", inject_globals(cleanup_validator_db), local.translate("cleanup_cmd")) console.AddItem("benchmark", inject_globals(run_benchmark), local.translate("benchmark_cmd")) + console.AddItem("activate_ton_storage_provider", inject_globals(activate_ton_storage_provider), local.translate("activate_ton_storage_provider_cmd")) # Process input parameters opts, args = getopt.getopt(argv,"hc:w:",["config=","wallets="]) @@ -176,6 +177,24 @@ def inject_globals(func): local.db.config.logLevel = "debug" if console.debug else "info" local.db.config.isLocaldbSaving = False local.run() +#end define + + +def activate_ton_storage_provider(local, ton, args): + wallet_name = "provider_wallet_001" + wallet = ton.GetLocalWallet(wallet_name) + account = ton.GetAccount(wallet.addrB64) + if account.status == "active": + color_print("activate_ton_storage_provider - {green}Already activated{endc}") + #return + ton.ActivateWallet(wallet) + destination = "0:7777777777777777777777777777777777777777777777777777777777777777" + ton_storage = ton.GetSettings("ton_storage") + comment = f"tsp-{ton_storage.provider.pubkey}" + flags = ["-n", "-C", comment] + ton.MoveCoins(wallet, destination, 0.01, flags=flags) + color_print("activate_ton_storage_provider - {green}OK{endc}") +#end define def check_installer_user(): diff --git a/mytoninstaller/config.py b/mytoninstaller/config.py index 871e691c..92fa474f 100644 --- a/mytoninstaller/config.py +++ b/mytoninstaller/config.py @@ -34,6 +34,14 @@ def SetConfig(**kwargs): #end define +def backup_config(local, config_path): + backup_path = f"{config_path}.backup" + local.add_log(f"Backup config file '{config_path}' to '{backup_path}'", "debug") + args = ["cp", config_path, backup_path] + subprocess.run(args) +#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 diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 466861b2..f5734f51 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -25,7 +25,9 @@ EnableTonHttpApi, DangerousRecoveryValidatorConfigFile, CreateSymlinks, - enable_ls_proxy + enable_ls_proxy, + enable_ton_storage, + enable_ton_storage_provider ) from mytoninstaller.config import ( CreateLocalConfig, @@ -172,6 +174,7 @@ def Enable(local, args): print("'JR' - jsonrpc") print("'THA' - ton-http-api") print("'LSP' - ls-proxy") + print("'TSP' - ton-storage + ton-storage-provider") print("Example: 'enable FN'") return if name == "THA": @@ -236,6 +239,9 @@ def Event(local, name): EnableTonHttpApi(local) if name == "enableLSP": enable_ls_proxy(local) + if name == "enableTSP": + enable_ton_storage(local) + enable_ton_storage_provider(local) if name == "clc": ix = sys.argv.index("-i") initBlock_b64 = sys.argv[ix+1] diff --git a/mytoninstaller/scripts/ls_proxy_installer.sh b/mytoninstaller/scripts/ls_proxy_installer.sh index 16630251..b20d6333 100644 --- a/mytoninstaller/scripts/ls_proxy_installer.sh +++ b/mytoninstaller/scripts/ls_proxy_installer.sh @@ -1,11 +1,12 @@ #!/bin/bash set -e +# import functions: check_superuser, get_cpu_number, check_go_version +my_dir=$(dirname $(realpath ${0})) +. ${my_dir}/utils.sh + # Проверить sudo -if [ "$(id -u)" != "0" ]; then - echo "Please run script as root" - exit 1 -fi +check_superuser # install parameters src_path=/usr/src @@ -40,64 +41,46 @@ ENDC='\033[0m' echo -e "${COLOR}[1/4]${ENDC} Cloning github repository" echo "https://github.com/${author}/${repo}.git -> ${branch}" + +package_src_path=${src_path}/${repo} +rm -rf ${package_src_path} + cd ${src_path} -rm -rf ${repo} git clone --branch=${branch} --recursive https://github.com/${author}/${repo}.git # Установка компонентов echo -e "${COLOR}[2/4]${ENDC} Installing required packages" - -arc=$(dpkg --print-architecture) -go_version_url=https://go.dev/VERSION?m=text -go_version=$(curl -s ${go_version_url} | head -n 1) -go_url=https://go.dev/dl/${go_version}.linux-${arc}.tar.gz go_path=/usr/local/go/bin/go -rm -rf /usr/local/go -wget -c ${go_url} -O - | tar -C /usr/local -xz - -# Расчитываем количество процессоров для сборки -if [[ "$OSTYPE" =~ darwin.* ]]; then - cpu_number=$(sysctl -n hw.logicalcpu) -else - memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') - cpu_number=$(($memory/2100000)) - max_cpu_number=$(nproc) - if [ ${cpu_number} -gt ${max_cpu_number} ]; then - cpu_number=$((${max_cpu_number}-1)) - fi - if [ ${cpu_number} == 0 ]; then - echo "Warning! insufficient RAM" - cpu_number=1 - fi -fi +check_go_version "${package_src_path}/go.mod" ${go_path} # Компилируем из исходников +cpu_number=$(get_cpu_number) echo -e "${COLOR}[3/4]${ENDC} Source compilation, use ${cpu_number} cpus" -proxy_src_path=${src_path}/${repo} -ton_src_path=${proxy_src_path}/ton -proxy_internal_path=${proxy_src_path}/internal/emulate/lib +ton_src_path=${package_src_path}/ton +proxy_internal_path=${package_src_path}/internal/emulate/lib proxy_build_path=${bin_path}/${bin_name} ton_build_path=${proxy_build_path}/ton -proxy_db_path=/var/${bin_name} -proxy_lib_path=${proxy_db_path}/lib +db_path=/var/${bin_name} +lib_path=${db_path}/lib -mkdir -p ${proxy_lib_path} +mkdir -p ${lib_path} mkdir -p ${ton_build_path} && cd ${ton_build_path} cmake -DCMAKE_BUILD_TYPE=Release -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=${openssl_path}/include -DOPENSSL_CRYPTO_LIBRARY=${openssl_path}/libcrypto.a ${ton_src_path} make emulator -j ${cpu_number} -cp ${ton_build_path}/emulator/libemulator.so ${proxy_lib_path} +cp ${ton_build_path}/emulator/libemulator.so ${lib_path} cp ${ton_build_path}/emulator/libemulator.so ${proxy_internal_path} cp ${ton_build_path}/emulator/emulator_export.h ${proxy_internal_path} # Компилируем -cd ${proxy_src_path} -CGO_ENABLED=1 ${go_path} build -o ${proxy_db_path}/${bin_name} ${proxy_src_path}/cmd/main.go +cd ${package_src_path} +entry_point=$(find ${package_src_path} -name "main.go" | head -n 1) +CGO_ENABLED=1 ${go_path} build -o ${db_path}/${bin_name} ${entry_point} # Настроить директорию работы -chown -R ${user}:${user} ${proxy_db_path} +chown -R ${user}:${user} ${db_path} # Выход из программы echo -e "${COLOR}[4/4]${ENDC} ${bin_name} installation complete" -exit 0 +exit 0 \ No newline at end of file diff --git a/mytoninstaller/scripts/ton_storage_installer.sh b/mytoninstaller/scripts/ton_storage_installer.sh new file mode 100644 index 00000000..262c1bee --- /dev/null +++ b/mytoninstaller/scripts/ton_storage_installer.sh @@ -0,0 +1,70 @@ +#!/bin/bash +set -e + +# import functions: check_superuser, check_go_version +my_dir=$(dirname $(realpath ${0})) +. ${my_dir}/utils.sh + +# Проверить sudo +check_superuser + +# install parameters +src_path=/usr/src +bin_path=/usr/bin + +# Get arguments +while getopts u:s:b: flag +do + case "${flag}" in + u) user=${OPTARG};; + s) src_path=${OPTARG};; + b) bin_path=${OPTARG};; + *) + echo "Flag -${flag} is not recognized. Aborting" + exit 1;; + esac +done + +# install parameters +author=xssnick +repo=tonutils-storage +branch=master +bin_name=ton_storage + +# Цвета +COLOR='\033[95m' +ENDC='\033[0m' + +# Клонирование репозиториев с github.com +echo -e "${COLOR}[1/4]${ENDC} Cloning github repository" +echo "https://github.com/${author}/${repo}.git -> ${branch}" + +package_src_path="${src_path}/${repo}" +rm -rf ${package_src_path} + +cd ${src_path} +git clone --branch=${branch} --recursive https://github.com/${author}/${repo}.git + +# Установка компонентов +echo -e "${COLOR}[2/4]${ENDC} Installing required packages" +go_path=/usr/local/go/bin/go +check_go_version "${package_src_path}/go.mod" ${go_path} + +# Компилируем из исходников +echo -e "${COLOR}[3/4]${ENDC} Source compilation" + +# Создать директорию работы +db_path="/var/${bin_name}" +mkdir -p ${db_path} + +# Компилируем +cd ${package_src_path} +#entry_point=$(find ${package_src_path} -name "main.go" | head -n 1) +CGO_ENABLED=1 ${go_path} build -o ${db_path}/${bin_name} ${package_src_path}/cli/main.go + +# Настроить директорию работы +chown -R ${user}:${user} ${db_path} + +# Выход из программы +echo -e "${COLOR}[4/4]${ENDC} ${bin_name} installation complete" +exit 0 diff --git a/mytoninstaller/scripts/ton_storage_provider_installer.sh b/mytoninstaller/scripts/ton_storage_provider_installer.sh new file mode 100644 index 00000000..1d4ac8cf --- /dev/null +++ b/mytoninstaller/scripts/ton_storage_provider_installer.sh @@ -0,0 +1,70 @@ +#!/bin/bash +set -e + +# import functions: check_superuser, check_go_version +my_dir=$(dirname $(realpath ${0})) +. ${my_dir}/utils.sh + +# Проверить sudo +check_superuser + +# install parameters +src_path=/usr/src +bin_path=/usr/bin + +# Get arguments +while getopts u:s:b: flag +do + case "${flag}" in + u) user=${OPTARG};; + s) src_path=${OPTARG};; + b) bin_path=${OPTARG};; + *) + echo "Flag -${flag} is not recognized. Aborting" + exit 1;; + esac +done + +# install parameters +author=xssnick +repo=tonutils-storage-provider +branch=master +bin_name=ton_storage_provider + +# Цвета +COLOR='\033[95m' +ENDC='\033[0m' + +# Клонирование репозиториев с github.com +echo -e "${COLOR}[1/4]${ENDC} Cloning github repository" +echo "https://github.com/${author}/${repo}.git -> ${branch}" + +package_src_path="${src_path}/${repo}" +rm -rf ${package_src_path} + +cd ${src_path} +git clone --branch=${branch} --recursive https://github.com/${author}/${repo}.git + +# Установка компонентов +echo -e "${COLOR}[2/4]${ENDC} Installing required packages" +go_path=/usr/local/go/bin/go +check_go_version "${package_src_path}/go.mod" ${go_path} + +# Компилируем из исходников +echo -e "${COLOR}[3/4]${ENDC} Source compilation" + +# Создать директорию работы +db_path="/var/${bin_name}" +mkdir -p ${db_path} + +# Компилируем +cd ${package_src_path} +#entry_point=$(find ${package_src_path} -name "main.go" | head -n 1) +CGO_ENABLED=1 ${go_path} build -o ${db_path}/${bin_name} ${package_src_path}/cmd/main.go + +# Настроить директорию работы +chown -R ${user}:${user} ${db_path} + +# Выход из программы +echo -e "${COLOR}[4/4]${ENDC} ${bin_name} installation complete" +exit 0 diff --git a/mytoninstaller/scripts/utils.sh b/mytoninstaller/scripts/utils.sh new file mode 100644 index 00000000..c304039c --- /dev/null +++ b/mytoninstaller/scripts/utils.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +check_superuser() { + if [ "$(id -u)" != "0" ]; then + echo "Please run script as root" + exit 1 + fi +} + +get_cpu_number() { + if [[ "$OSTYPE" =~ darwin.* ]]; then + cpu_number=$(sysctl -n hw.logicalcpu) + else + memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') + cpu_number=$(($memory/2100000)) + max_cpu_number=$(nproc) + if [ ${cpu_number} -gt ${max_cpu_number} ]; then + cpu_number=$((${max_cpu_number}-1)) + fi + if [ ${cpu_number} == 0 ]; then + echo "Warning! insufficient RAM" + cpu_number=1 + fi + fi + echo ${cpu_number} +} + +check_go_version() { + go_mod_path=${1} + go_path=${2} + go_mod_text=$(cat ${go_mod_path}) || exit 1 + need_version_text=$(echo "${go_mod_text}" | grep "go " | head -n 1 | awk '{print $2}') + current_version_text=$(${go_path} version | awk '{print $3}' | sed 's\go\\g') + echo "start check_go_version function, need_version: ${need_version_text}, current_version: ${current_version_text}" + current_version_1=$(echo ${current_version_text} | cut -d "." -f 1) + current_version_2=$(echo ${current_version_text} | cut -d "." -f 2) + current_version_3=$(echo ${current_version_text} | cut -d "." -f 3) + need_version_1=$(echo ${need_version_text} | cut -d "." -f 1) + need_version_2=$(echo ${need_version_text} | cut -d "." -f 2) + need_version_3=$(echo ${need_version_text} | cut -d "." -f 3) + if (( need_version_1 > current_version_1 )) || ((need_version_2 > current_version_2 )) || ((need_version_3 > current_version_3 )); then + install_go + fi +} + +install_go() { + echo "start install_go function" + arc=$(dpkg --print-architecture) + go_version_url=https://go.dev/VERSION?m=text + go_version=$(curl -s ${go_version_url} | head -n 1) + go_url=https://go.dev/dl/${go_version}.linux-${arc}.tar.gz + rm -rf /usr/local/go + wget -c ${go_url} -O - | tar -C /usr/local -xz +} diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index f1c73a4f..941e16cc 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -17,7 +17,7 @@ Dict ) from mytoninstaller.utils import StartValidator, StartMytoncore, start_service, stop_service, get_ed25519_pubkey -from mytoninstaller.config import SetConfig, GetConfig, get_own_ip +from mytoninstaller.config import SetConfig, GetConfig, get_own_ip, backup_config from mytoncore.utils import hex2b64 @@ -439,8 +439,8 @@ def EnableJsonRpc(local): 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: + exit_code = run_as_root(["bash", jsonrpcinstaller_path, "-u", user]) # TODO: fix path + if exit_code == 0: text = "EnableJsonRpc - {green}OK{endc}" else: text = "EnableJsonRpc - {red}Error{endc}" @@ -452,8 +452,8 @@ def EnableTonHttpApi(local): 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: + exit_code = run_as_root(["bash", ton_http_api_installer_path, "-u", user]) + if exit_code == 0: text = "EnableTonHttpApi - {green}OK{endc}" else: text = "EnableTonHttpApi - {red}Error{endc}" @@ -472,9 +472,10 @@ def enable_ls_proxy(local): installer_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'ls_proxy_installer.sh') local.add_log(f"Running script: {installer_path}", "debug") - exitCode = run_as_root(["bash", installer_path, "-u", user]) - if exitCode != 0: + exit_code = run_as_root(["bash", installer_path, "-u", user]) + if exit_code != 0: color_print("enable_ls_proxy - {red}Error{endc}") + raise Exception("enable_ls_proxy - Error") #end if # Прописать автозагрузку @@ -519,6 +520,142 @@ def enable_ls_proxy(local): color_print("enable_ls_proxy - {green}OK{endc}") #end define +def enable_ton_storage(local): + local.add_log("start enable_ton_storage function", "debug") + user = local.buffer.user + udp_port = random.randint(2000, 65000) + api_port = random.randint(2000, 65000) + bin_name = "ton_storage" + db_path = f"/var/{bin_name}" + bin_path = f"{db_path}/{bin_name}" + config_path = f"{db_path}/tonutils-storage-db/config.json" + network_config = "/usr/bin/ton/global.config.json" + + installer_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'ton_storage_installer.sh') + local.add_log(f"Running script: {installer_path}", "debug") + exit_code = run_as_root(["bash", installer_path, "-u", user]) + if exit_code != 0: + color_print("enable_ton_storage - {red}Error{endc}") + raise Exception("enable_ton_storage - Error") + #end if + + # Прописать автозагрузку + start_cmd = f"{bin_path} -network-config {network_config} -daemon -api 127.0.0.1:{api_port}" + add2systemd(name=bin_name, user=user, start=start_cmd, workdir=db_path, force=True) + + # Первый запуск - создание конфига + start_service(local, bin_name, sleep=10) + stop_service(local, bin_name) + + # read ton_storage config + local.add_log("read ton_storage config", "debug") + ton_storage_config = GetConfig(path=config_path) + + # prepare config + ton_storage_config.ListenAddr = f"0.0.0.0:{udp_port}" + ton_storage_config.ExternalIP = get_own_ip() + + # write ton_storage config + local.add_log("write ton_storage config", "debug") + SetConfig(path=config_path, data=ton_storage_config) + + # backup config + backup_config(local, config_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") + ton_storage = Dict() + ton_storage.udp_port = udp_port + ton_storage.api_port = api_port + mconfig.ton_storage = ton_storage + + # write mconfig + local.add_log("write mconfig", "debug") + SetConfig(path=mconfig_path, data=mconfig) + + # start ton_storage + start_service(local, bin_name) + color_print("enable_ton_storage - {green}OK{endc}") +#end define + +def enable_ton_storage_provider(local): + local.add_log("start enable_ton_storage_provider function", "debug") + user = local.buffer.user + udp_port = random.randint(2000, 65000) + bin_name = "ton_storage_provider" + db_path = f"/var/{bin_name}" + bin_path = f"{db_path}/{bin_name}" + config_path = f"{db_path}/config.json" + network_config = "/usr/bin/ton/global.config.json" + + installer_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'ton_storage_provider_installer.sh') + local.add_log(f"Running script: {installer_path}", "debug") + exit_code = run_as_root(["bash", installer_path, "-u", user]) + if exit_code != 0: + color_print("enable_ton_storage_provider - {red}Error{endc}") + raise Exception("enable_ton_storage_provider - Error") + #end if + + # Прописать автозагрузку + start_cmd = f"{bin_path} -network-config {network_config}" + add2systemd(name=bin_name, user=user, start=start_cmd, workdir=db_path, force=True) + + # Первый запуск - создание конфига + start_service(local, bin_name, sleep=10) + stop_service(local, bin_name) + + # read mconfig + local.add_log("read mconfig", "debug") + mconfig_path = local.buffer.mconfig_path + mconfig = GetConfig(path=mconfig_path) + + # read ton_storage_provider config + local.add_log("read ton_storage_provider config", "debug") + config = GetConfig(path=config_path) + + # prepare config + config.ListenAddr = f"0.0.0.0:{udp_port}" + config.ExternalIP = get_own_ip() + config.Storages[0].BaseURL = f"http://127.0.0.1:{mconfig.ton_storage.api_port}" + + # write ton_storage_provider config + local.add_log("write ton_storage_provider config", "debug") + SetConfig(path=config_path, data=config) + + # backup config + backup_config(local, config_path) + + # get provider pubkey + key_bytes = base64.b64decode(config.ProviderKey) + pubkey_bytes = key_bytes[32:64] + + # edit mytoncore config file + local.add_log("edit mytoncore config file", "debug") + provider = Dict() + provider.udp_port = udp_port + provider.config_path = config_path + provider.pubkey = pubkey_bytes.hex() + mconfig.ton_storage.provider = provider + + # write mconfig + local.add_log("write mconfig", "debug") + SetConfig(path=mconfig_path, data=mconfig) + + # Подтянуть событие в mytoncore.py + cmd = 'python3 -m mytoncore -e "enable_ton_storage_provider"' + args = ["su", "-l", user, "-c", cmd] + subprocess.run(args) + + # start ton_storage_provider + start_service(local, bin_name) + color_print("enable_ton_storage_provider - {green}OK{endc}") +#end define + def DangerousRecoveryValidatorConfigFile(local): local.add_log("start DangerousRecoveryValidatorConfigFile function", "info") From ad3abf2f8c4dd1973868dff3742efb93549093f2 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 28 Mar 2024 16:08:36 +0800 Subject: [PATCH 160/236] add cpu info to telemetry --- mytoncore/functions.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index ffb9a3ef..f300099c 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -20,6 +20,7 @@ thr_sleep, Dict ) +from mytoninstaller.node_args import get_node_args def Init(local): @@ -460,6 +461,26 @@ def get_db_stats(): # end define +def get_cpu_name(): + with open('/proc/cpuinfo') as f: + for line in f: + if line.strip(): + if line.rstrip('\n').startswith('model name'): + return line.rstrip('\n').split(':')[1].strip() + return None + + +def is_host_virtual(): + try: + with open('/sys/class/dmi/id/product_name') as f: + product_name = f.read().strip().lower() + if 'virtual' in product_name or 'kvm' in product_name or 'qemu' in product_name or 'vmware' in product_name: + return {'virtual': True, 'product_name': product_name} + return {'virtual': False, 'product_name': product_name} + except FileNotFoundError: + return {'virtual': None, 'product_name': None} + + def Telemetry(local, ton): sendTelemetry = local.db.get("sendTelemetry") if sendTelemetry is not True: @@ -484,6 +505,8 @@ def Telemetry(local, ton): data["uname"] = GetUname() data["vprocess"] = GetValidatorProcessInfo() data["dbStats"] = get_db_stats() + data["nodeArgs"] = get_node_args() + data["cpuInfo"] = {'cpuName': get_cpu_name(), 'virtual': is_host_virtual()} elections = local.try_function(ton.GetElectionEntries) complaints = local.try_function(ton.GetComplaints) From 2a8b926c0dec567abe4fcfd61c0452d6556eea3e Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 28 Mar 2024 23:23:07 +0800 Subject: [PATCH 161/236] telemetry improves --- mytoncore/functions.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index f300099c..134d94d2 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -481,6 +481,29 @@ def is_host_virtual(): return {'virtual': None, 'product_name': None} +def do_beacon_ping(host, count, timeout): + args = ['ping', '-c', str(count), '-W', str(timeout), host] + process = subprocess.run(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + output = process.stdout.decode("utf-8") + avg = output.split('\n')[-1].split('=')[1].split('/')[1] + return float(avg) + + +def get_pings_values(): + return { + 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 1, 3), + 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 1, 3) + } + + +def get_validator_disk_name(): + process = subprocess.run("df -h /var/ton-work/ | sed -n '2 p' | awk '{print $1}'", stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3, shell=True) + output = process.stdout.decode("utf-8") + return output.strip() + + def Telemetry(local, ton): sendTelemetry = local.db.get("sendTelemetry") if sendTelemetry is not True: @@ -507,6 +530,8 @@ def Telemetry(local, ton): data["dbStats"] = get_db_stats() data["nodeArgs"] = get_node_args() data["cpuInfo"] = {'cpuName': get_cpu_name(), 'virtual': is_host_virtual()} + data["validatorDiskName"] = get_validator_disk_name() + data["pings"] = get_pings_values() elections = local.try_function(ton.GetElectionEntries) complaints = local.try_function(ton.GetComplaints) From 63492ade67d989eb1c0573592c6299115359d3d1 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 28 Mar 2024 23:44:04 +0800 Subject: [PATCH 162/236] add about cmd --- mytonctrl/mytonctrl.py | 16 ++++++++++++++++ mytonctrl/resources/translate.json | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 3477c0f1..a716483d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -72,6 +72,7 @@ def inject_globals(func): console.AddItem("status_modes", inject_globals(mode_status), local.translate("status_modes_cmd")) console.AddItem("enable_mode", inject_globals(enable_mode), local.translate("enable_mode_cmd")) console.AddItem("disable_mode", inject_globals(disable_mode), local.translate("disable_mode_cmd")) + console.AddItem("about", inject_globals(about), local.translate("about_cmd")) console.AddItem("get", inject_globals(GetSettings), local.translate("get_cmd")) console.AddItem("set", inject_globals(SetSettings), local.translate("set_cmd")) console.AddItem("rollback", inject_globals(rollback_to_mtc1), local.translate("rollback_cmd")) @@ -176,6 +177,21 @@ def inject_globals(func): local.db.config.logLevel = "debug" if console.debug else "info" local.db.config.isLocaldbSaving = False local.run() +#end define + + +def about(local, ton, args): + if len(args) != 1: + color_print("{red}Bad args. Usage:{endc} about ") + mode_name = args[0] + mode = ton.get_mode(mode_name) + if mode is None: + color_print(f"{{red}}Mode {mode_name} not found{{endc}}") + return + color_print(f'''{{cyan}}===[ {mode_name} MODE ]==={{cyan}}=''') + color_print(f'''Description: {mode.description}''') + color_print('Enabled: ' + color_text('{green}yes{endc}' if ton.get_mode_value(mode_name) else '{red}no{endc}')) +#end define def check_installer_user(): diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index ef5e897c..7a5f7c28 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -19,6 +19,11 @@ "ru": "Показать режимы MTC", "zh_TW": "顯示 MTC 模式" }, + "about_cmd": { + "en": "Mode description", + "ru": "Описание режима", + "zh_TW": "模式描述" + }, "enable_mode_cmd": { "en": "Enable mode", "ru": "Включить режим", From e657e6d118bd63a6cb7886eacbe17a09f97bd32d Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 29 Mar 2024 19:21:09 +0300 Subject: [PATCH 163/236] do_beacon_ping bugfix --- mytoncore/functions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 87559a86..6ed024f4 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -499,7 +499,9 @@ def do_beacon_ping(host, count, timeout): process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) output = process.stdout.decode("utf-8") - avg = output.split('\n')[-1].split('=')[1].split('/')[1] + output_lines = output.split('\n') + rtt_line = list(filter(None, output_lines))[-1] + avg = rtt_line.split('=')[1].split('/')[1] return float(avg) From 1ed5032d601a7e132dd9156d23200bc9e933f1a3 Mon Sep 17 00:00:00 2001 From: yungwine Date: Sat, 30 Mar 2024 13:21:46 +0800 Subject: [PATCH 164/236] update pings --- mytoncore/functions.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 6ed024f4..f04d9193 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -499,16 +499,14 @@ def do_beacon_ping(host, count, timeout): process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) output = process.stdout.decode("utf-8") - output_lines = output.split('\n') - rtt_line = list(filter(None, output_lines))[-1] - avg = rtt_line.split('=')[1].split('/')[1] + avg = output.split('\n')[-2].split('=')[1].split('/')[1] return float(avg) def get_pings_values(): return { - 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 1, 3), - 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 1, 3) + 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 5, 3), + 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 5, 3) } From 9aa9041449ac4da92d3f211735fef629d92da429 Mon Sep 17 00:00:00 2001 From: yungwine Date: Sat, 30 Mar 2024 13:22:44 +0800 Subject: [PATCH 165/236] bugfix --- mytoncore/functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index f04d9193..f90e9038 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -505,8 +505,8 @@ def do_beacon_ping(host, count, timeout): def get_pings_values(): return { - 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 5, 3), - 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 5, 3) + 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 5, 10), + 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 5, 10) } From b74141deff33b8be3ae6449ae98dbe4b85ee8638 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 1 Apr 2024 12:02:07 +0800 Subject: [PATCH 166/236] fix set_node_argument --- mytoninstaller/mytoninstaller.py | 11 ----------- mytoninstaller/node_args.py | 20 ++++++++++++++++++-- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 29d9cf78..026c2423 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -134,16 +134,6 @@ def Status(local, args): #end define -def restart_node(): - exit_code = run_as_root(["systemctl", "daemon-reload"]) - if exit_code: - raise Exception(f"`systemctl daemon-reload` failed with exit code {exit_code}") - exit_code = run_as_root(["systemctl", "restart", "validator"]) - if exit_code: - raise Exception(f"`systemctl restart validator` failed with exit code {exit_code}") -#end define - - def set_node_argument(local, args): if len(args) < 1: color_print("{red}Bad args. Usage:{endc} set_node_argument [arg-value] [-d (to delete)]") @@ -157,7 +147,6 @@ def set_node_argument(local, args): set_node_arg(arg_name, None) else: set_node_arg(arg_name, arg_value) - restart_node() color_print("set_node_argument - {green}OK{endc}") #end define diff --git a/mytoninstaller/node_args.py b/mytoninstaller/node_args.py index 96abbcfb..6b451ec4 100644 --- a/mytoninstaller/node_args.py +++ b/mytoninstaller/node_args.py @@ -1,9 +1,11 @@ +from mypylib.mypylib import run_as_root def get_validator_service(): path = '/etc/systemd/system/validator.service' with open(path, 'r') as f: return f.read() +#end define def get_node_start_command(): @@ -11,6 +13,7 @@ def get_node_start_command(): for line in service.split('\n'): if 'ExecStart' in line: return line.split('=')[1].strip() +#end define def get_node_args(command: str = None): @@ -29,6 +32,17 @@ def get_node_args(command: str = None): if key: result[key] = '' return result +#end define + + +def restart_node(): + exit_code = run_as_root(["systemctl", "daemon-reload"]) + if exit_code: + raise Exception(f"`systemctl daemon-reload` failed with exit code {exit_code}") + exit_code = run_as_root(["systemctl", "restart", "validator"]) + if exit_code: + raise Exception(f"`systemctl restart validator` failed with exit code {exit_code}") +#end define def set_node_arg(arg_name: str, arg_value: str = ''): @@ -49,5 +63,7 @@ def set_node_arg(arg_name: str, arg_value: str = ''): args[arg_name] = arg_value new_command = command.split(' ')[0] + ' ' + ' '.join([f'{k} {v}' for k, v in args.items()]) new_service = service.replace(command, new_command) - with open('/etc/systemd/system/validator.service', 'w') as f: - f.write(new_service) + c = f"with open('/etc/systemd/system/validator.service', 'w') as f: f.write('''{new_service}''')" + run_as_root(['python3', '-c', f'"{c}"']) + restart_node() +#end define From d00a8d0d3a34f29cce9479a448e22cac680183b5 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 1 Apr 2024 13:54:44 +0300 Subject: [PATCH 167/236] CreateWallet bugfix --- mytoncore/mytoncore.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 6498a191..16c70279 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1650,10 +1650,10 @@ def SaveElectionVarsToJsonFile(self, **kwargs): def CreateWallet(self, name, workchain=0, version="v1", **kwargs): 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: + subwallet_default = 698983191 + workchain # 0x29A9A317 + workchain + subwallet = kwargs.get("subwallet", subwallet_default) + wallet_path = self.walletsDir + name + if os.path.isfile(wallet_path + ".pk") and "v3" not in version: self.local.add_log("CreateWallet error: Wallet already exists: " + name, "warning") else: fift_args = self.get_new_wallet_fift_args(version, workchain=workchain, @@ -1670,15 +1670,15 @@ def CreateWallet(self, name, workchain=0, version="v1", **kwargs): def CreateHighWallet(self, name, **kwargs): workchain = kwargs.get("workchain", 0) - subwalletDefault = 698983191 + workchain # 0x29A9A317 + workchain - subwallet = kwargs.get("subwallet", subwalletDefault) + subwallet_default = 698983191 + workchain # 0x29A9A317 + workchain + subwallet = kwargs.get("subwallet", subwallet_default) version = kwargs.get("version", "hv1") 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"): + wallet_path = self.walletsDir + name + if os.path.isfile(wallet_path + ".pk") and os.path.isfile(wallet_path + str(subwallet) + ".addr"): self.local.AddLog("CreateHighWallet error: Wallet already exists: " + name + str(subwallet), "warning") else: - args = ["new-highload-wallet.fif", workchain, subwallet, walletPath] + args = ["new-highload-wallet.fif", workchain, subwallet, wallet_path] result = self.fift.Run(args) if "Creating new high-load wallet" not in result: raise Exception("CreateHighWallet error") From 13ffb279d9d89f1f85f3e42e41c3876633f1832a Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 1 Apr 2024 19:46:37 +0800 Subject: [PATCH 168/236] fix set node args --- mytoninstaller/mytoninstaller.py | 13 +++---- mytoninstaller/node_args.py | 34 ---------------- mytoninstaller/scripts/set_node_argument.py | 43 +++++++++++++++++++++ 3 files changed, 48 insertions(+), 42 deletions(-) create mode 100644 mytoninstaller/scripts/set_node_argument.py diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 026c2423..0915c253 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -7,6 +7,8 @@ import json import subprocess +import pkg_resources + from mypylib.mypylib import MyPyClass, run_as_root, color_print from mypyconsole.mypyconsole import MyPyConsole @@ -139,14 +141,9 @@ def set_node_argument(local, args): color_print("{red}Bad args. Usage:{endc} set_node_argument [arg-value] [-d (to delete)]") return arg_name = args[0] - if len(args) == 1: - set_node_arg(arg_name) - else: - arg_value = args[1] - if arg_value == "-d": - set_node_arg(arg_name, None) - else: - set_node_arg(arg_name, arg_value) + args = [arg_name, args[1] if len(args) > 1 else ""] + script_path = pkg_resources.resource_filename('mytoninstaller.scripts', 'set_node_argument.py') + run_as_root(['python3', script_path] + args) color_print("set_node_argument - {green}OK{endc}") #end define diff --git a/mytoninstaller/node_args.py b/mytoninstaller/node_args.py index 6b451ec4..ec99eea3 100644 --- a/mytoninstaller/node_args.py +++ b/mytoninstaller/node_args.py @@ -1,4 +1,3 @@ -from mypylib.mypylib import run_as_root def get_validator_service(): @@ -34,36 +33,3 @@ def get_node_args(command: str = None): return result #end define - -def restart_node(): - exit_code = run_as_root(["systemctl", "daemon-reload"]) - if exit_code: - raise Exception(f"`systemctl daemon-reload` failed with exit code {exit_code}") - exit_code = run_as_root(["systemctl", "restart", "validator"]) - if exit_code: - raise Exception(f"`systemctl restart validator` failed with exit code {exit_code}") -#end define - - -def set_node_arg(arg_name: str, arg_value: str = ''): - """ - :param arg_name: - :param arg_value: arg value. if None, remove the arg; if empty string, argument is set without value - :return: - """ - assert arg_name.startswith('-'), 'arg_name must start with "-" or "--"' - service = get_validator_service() - command = get_node_start_command() - if command is None: - raise Exception('Cannot find node start command in service file') - args = get_node_args(command) - if arg_value is None: - args.pop(arg_name, None) - else: - args[arg_name] = arg_value - new_command = command.split(' ')[0] + ' ' + ' '.join([f'{k} {v}' for k, v in args.items()]) - new_service = service.replace(command, new_command) - c = f"with open('/etc/systemd/system/validator.service', 'w') as f: f.write('''{new_service}''')" - run_as_root(['python3', '-c', f'"{c}"']) - restart_node() -#end define diff --git a/mytoninstaller/scripts/set_node_argument.py b/mytoninstaller/scripts/set_node_argument.py new file mode 100644 index 00000000..b347b5b5 --- /dev/null +++ b/mytoninstaller/scripts/set_node_argument.py @@ -0,0 +1,43 @@ +import sys +import subprocess +from mytoninstaller.node_args import get_node_args, get_node_start_command, get_validator_service + + +def set_node_arg(arg_name: str, arg_value: str = ''): + """ + :param arg_name: + :param arg_value: arg value. if None, remove the arg; if empty string, argument is set without value + :return: + """ + assert arg_name.startswith('-'), 'arg_name must start with "-" or "--"' + service = get_validator_service() + command = get_node_start_command() + if command is None: + raise Exception('Cannot find node start command in service file') + args = get_node_args(command) + if arg_value == '-d': + args.pop(arg_name, None) + else: + args[arg_name] = arg_value + new_command = command.split(' ')[0] + ' ' + ' '.join([f'{k} {v}' for k, v in args.items()]) + new_service = service.replace(command, new_command) + with open('/etc/systemd/system/validator.service', 'w') as f: + f.write(new_service) + restart_node() +#end define + + +def restart_node(): + exit_code = subprocess.run(["systemctl", "daemon-reload"]).returncode + if exit_code: + raise Exception(f"`systemctl daemon-reload` failed with exit code {exit_code}") + exit_code = subprocess.run(["systemctl", "restart", "validator"]).returncode + if exit_code: + raise Exception(f"`systemctl restart validator` failed with exit code {exit_code}") +#end define + + +if __name__ == '__main__': + name = sys.argv[1] + value = sys.argv[2] if len(sys.argv) > 2 else '' + set_node_arg(name, value) From 53a5171db972c9a37947a7c56c575b27cb6bd24e Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 1 Apr 2024 22:45:40 +0800 Subject: [PATCH 169/236] bugifx --- mytoninstaller/mytoninstaller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 0915c253..56daf47e 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -13,7 +13,7 @@ from mypyconsole.mypyconsole import MyPyConsole from mytoninstaller.config import GetLiteServerConfig, get_ls_proxy_config -from mytoninstaller.node_args import get_node_args, set_node_arg +from mytoninstaller.node_args import get_node_args from mytoninstaller.utils import GetInitBlock from mytoncore.utils import dict2b64, str2bool, b642dict From 981b5be449e101431867640cc59430cf9741c3e5 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 10 Apr 2024 15:29:20 +0800 Subject: [PATCH 170/236] add custom overlays fix logging bugfix add custom overlays to mytonctrl add custom overlays add custom overlay methods to mytoncore --- modules/custom_overlays.py | 181 +++++++++++++++++++++++++++++++++++++ mytoncore/functions.py | 4 + mytoncore/mytoncore.py | 15 +++ mytonctrl/mytonctrl.py | 4 + 4 files changed, 204 insertions(+) create mode 100644 modules/custom_overlays.py diff --git a/modules/custom_overlays.py b/modules/custom_overlays.py new file mode 100644 index 00000000..e951318c --- /dev/null +++ b/modules/custom_overlays.py @@ -0,0 +1,181 @@ +import json +import requests + +from mypylib.mypylib import color_print +from modules.module import MtcModule +from mytoncore.utils import hex2base64 + + +class CustomOverlayModule(MtcModule): + + @staticmethod + def parse_config(name: str, config: dict, vset: list = None): + """ + Converts config to validator-console friendly format + :param name: custom overlay name + :param config: config + :param vset: list of validators adnl addresses, can be None if `@validators` not in config + :return: + """ + result = { + "name": name, + "nodes": [] + } + for k, v in config.items(): + if k == '@validators' and v: + if vset is None: + raise Exception("Validators set is not defined but @validators is in config") + for v_adnl in vset: + result["nodes"].append({ + "adnl_id": hex2base64(v_adnl), + "msg_sender": False, + }) + else: + result["nodes"].append({ + "adnl_id": hex2base64(k), + "msg_sender": v["msg_sender"], + }) + if v["msg_sender"]: + result["nodes"][-1]["msg_sender_priority"] = v["msg_sender_priority"] + return result + + def add_custom_overlay(self, args): + if len(args) != 2: + color_print("{red}Bad args. Usage:{endc} add_custom_overlay ") + return + path = args[1] + with open(path, 'r') as f: + config = json.load(f) + self.ton.set_custom_overlay(args[0], config) + if '@validators' in config: + print('Dynamic overlay will be added within 1 minute') + else: + result = self.add_custom_overlay_to_vc(self.parse_config(args[0], config)) + if not result: + print('Failed to add overlay to validator console') + color_print("add_custom_overlay - {red}ERROR{endc}") + return + color_print("add_custom_overlay - {green}OK{endc}") + + def list_custom_overlays(self, args): + if not self.ton.get_custom_overlays(): + color_print("{red}No custom overlays{endc}") + return + for k, v in self.ton.get_custom_overlays().items(): + color_print(f"Custom overlay {{bold}}{k}{{endc}}:") + print(json.dumps(v, indent=4)) + + def delete_custom_overlay(self, args): + if len(args) != 1: + color_print("{red}Bad args. Usage:{endc} delete_custom_overlay ") + return + if '@validators' in self.ton.get_custom_overlays().get(args[0], {}): + self.ton.delete_custom_overlay(args[0]) + print('Dynamic overlay will be deleted within 1 minute') + else: + self.ton.delete_custom_overlay(args[0]) + result = self.delete_custom_overlay_from_vc(args[0]) + if not result: + print('Failed to delete overlay from validator console') + color_print("delete_custom_overlay - {red}ERROR{endc}") + return + color_print("delete_custom_overlay - {green}OK{endc}") + + def check_node_eligible_for_custom_overlay(self, config: dict): + vconfig = self.ton.GetValidatorConfig() + my_adnls = vconfig.adnl + node_adnls = [i["adnl_id"] for i in config["nodes"]] + for adnl in my_adnls: + if adnl.id in node_adnls: + return True + return False + + def delete_custom_overlay_from_vc(self, name: str): + result = self.ton.validatorConsole.Run(f"delcustomoverlay {name}") + return 'success' in result + + def add_custom_overlay_to_vc(self, config: dict): + if not self.check_node_eligible_for_custom_overlay(config): + self.ton.local.add_log(f"Node has no adnl address required for custom overlay {config.get('name')}", "debug") + return False + self.ton.local.add_log(f"Adding custom overlay {config.get('name')}", "debug") + path = self.ton.tempDir + f'/custom_overlay_{config["name"]}.json' + with open(path, 'w') as f: + json.dump(config, f) + result = self.ton.validatorConsole.Run(f"addcustomoverlay {path}") + return 'success' in result + + def custom_overlays(self): + config = self.get_default_custom_overlay() + if config is not None: + self.ton.set_custom_overlay('default', config) + self.deploy_custom_overlays() + + def deploy_custom_overlays(self): + result = self.ton.validatorConsole.Run("showcustomoverlays") + if 'unknown command' in result: + return # node old version + names = [] + for line in result.split('\n'): + if line.startswith('Overlay'): + names.append(line.split(' ')[1].replace('"', '').replace(':', '')) + + config34 = self.ton.GetConfig34() + current_el_id = config34['startWorkTime'] + current_vset = [i["adnlAddr"] for i in config34['validators']] + + config36 = self.ton.GetConfig36() + next_el_id = config36['startWorkTime'] if config36['validators'] else 0 + next_vset = [i["adnlAddr"] for i in config36['validators']] + + for name in names: + # check that overlay still exists in mtc db + pure_name = name + suffix = name.split('_')[-1] + if suffix.startswith('elid') and suffix.split('elid')[-1].isdigit(): # probably election id + pure_name = '_'.join(name.split('_')[:-1]) + el_id = int(suffix.split('elid')[-1]) + if el_id not in (current_el_id, next_el_id): + self.ton.local.add_log(f"Overlay {name} is not in current or next election, deleting", "debug") + self.delete_custom_overlay_from_vc(name) # delete overlay if election id is not in current or next election + continue + + if pure_name not in self.ton.get_custom_overlays(): + self.ton.local.add_log(f"Overlay {name} ({pure_name}) is not in mtc db, deleting", "debug") + self.delete_custom_overlay_from_vc(name) # delete overlay if it's not in mtc db + + for name, config in self.ton.get_custom_overlays().items(): + if name in names: + continue + if '@validators' in config: + new_name = name + '_elid' + str(current_el_id) + if new_name not in names: + node_config = self.parse_config(new_name, config, current_vset) + self.add_custom_overlay_to_vc(node_config) + + if next_el_id != 0: + new_name = name + '_elid' + str(next_el_id) + if new_name not in names: + node_config = self.parse_config(new_name, config, next_vset) + self.add_custom_overlay_to_vc(node_config) + else: + node_config = self.parse_config(name, config) + self.add_custom_overlay_to_vc(node_config) + + def get_default_custom_overlay(self): + if not self.ton.local.db.get('useDefaultCustomOverlays', True): + return None + network = self.ton.GetNetworkName() + default_url = 'https://ton-blockchain.github.io/fallback_custom_overlays.json' + url = self.ton.local.db.get('defaultCustomOverlaysUrl', default_url) + resp = requests.get(url) + if resp.status_code != 200: + self.ton.local.add_log(f"Failed to get default custom overlays from {url}", "error") + return None + config = resp.json() + return config.get(network) + + def add_console_commands(self, console): + console.AddItem("add_custom_overlay", self.add_custom_overlay, self.local.translate("add_custom_overlay_cmd")) + console.AddItem("list_custom_overlays", self.list_custom_overlays, self.local.translate("list_custom_overlays_cmd")) + console.AddItem("delete_custom_overlay", self.delete_custom_overlay, self.local.translate("delete_custom_overlay_cmd")) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index f90e9038..c7a3d373 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -690,6 +690,10 @@ def General(local): 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,)) + + from modules.custom_overlays import CustomOverlayModule + local.start_cycle(CustomOverlayModule(ton, local).custom_overlays, sec=60, args=()) + thr_sleep() # end define diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 6498a191..133d5c60 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3910,6 +3910,21 @@ def ControllerRecoverStake(self, controllerAddr): self.local.add_log("ControllerRecoverStake completed") #end define + def get_custom_overlays(self): + if 'custom_overlays' not in self.local.db: + self.local.db['custom_overlays'] = {} + return self.local.db['custom_overlays'] + + def set_custom_overlay(self, name: str, config: dict): + overlays = self.get_custom_overlays() + overlays[name] = config + self.local.save() + + def delete_custom_overlay(self, name: str): + del self.local.db['custom_overlays'][name] + self.local.save() + + def GetNetworkName(self): data = self.local.read_db(self.liteClient.configPath) mainnet_zero_state_root_hash = "F6OpKZKqvqeFp6CQmFomXNMfMj2EnaUSOXN+Mh+wVWk=" diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 9c407dd7..7d9865c8 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -120,6 +120,10 @@ def inject_globals(func): #console.AddItem("ssoc", inject_globals(SignShardOverlayCert), local.translate("ssoc_cmd")) #console.AddItem("isoc", inject_globals(ImportShardOverlayCert), local.translate("isoc_cmd")) + from modules.custom_overlays import CustomOverlayModule + module = CustomOverlayModule(ton, local) + module.add_console_commands(console) + if ton.using_validator(): from modules.validator import ValidatorModule module = ValidatorModule(ton, local) From 1086f3cd628295b989dcd5c442fca04a052decdf Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 11:22:09 +0800 Subject: [PATCH 171/236] check if start command is default in set_node_argument --- mytoninstaller/scripts/set_node_argument.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mytoninstaller/scripts/set_node_argument.py b/mytoninstaller/scripts/set_node_argument.py index b347b5b5..19fe67a5 100644 --- a/mytoninstaller/scripts/set_node_argument.py +++ b/mytoninstaller/scripts/set_node_argument.py @@ -12,6 +12,8 @@ def set_node_arg(arg_name: str, arg_value: str = ''): assert arg_name.startswith('-'), 'arg_name must start with "-" or "--"' service = get_validator_service() command = get_node_start_command() + if command.split(' ')[0] != '/usr/bin/ton/validator-engine/validator-engine': + raise Exception('Invalid node start command in service file') if command is None: raise Exception('Cannot find node start command in service file') args = get_node_args(command) From 65f664eaaa1a8329a33716486be1b95939880a5f Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 12:05:40 +0800 Subject: [PATCH 172/236] add settings checking in set --- modules/__init__.py | 53 +++++++++++++++++++++++++++++++++++++----- mytonctrl/mytonctrl.py | 19 ++++++++++++++- 2 files changed, 65 insertions(+), 7 deletions(-) diff --git a/modules/__init__.py b/modules/__init__.py index 5fe73d82..9c8c381b 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -1,11 +1,12 @@ import typing +from dataclasses import dataclass -from .module import MtcModule -from .pool import PoolModule -from .nominator_pool import NominatorPoolModule -from .single_pool import SingleNominatorModule -from .validator import ValidatorModule -from .controller import ControllerModule +from modules.module import MtcModule +from modules.pool import PoolModule +from modules.nominator_pool import NominatorPoolModule +from modules.single_pool import SingleNominatorModule +from modules.validator import ValidatorModule +from modules.controller import ControllerModule MODES = { @@ -18,3 +19,43 @@ def get_mode(mode_name: str) -> typing.Optional[MtcModule]: return MODES.get(mode_name) + + +@dataclass +class Setting: + mode: typing.Optional[str] + default_value: typing.Any + description: str + + +SETTINGS = { + 'stake': Setting('validator', False, 'Stake amount'), + 'stakePercent': Setting('validator', 99, 'Stake percent if `stake` is null'), + 'isSlashing': Setting('validator', None, 'Create complaints to validators'), + 'maxFactor': Setting('validator', None, 'Param send to Elector. if null will be taken from 17 config param'), + 'participateBeforeEnd': Setting('validator', None, 'Amount of seconds before start of round to participate'), + 'liquid_pool_addr': Setting('liquid-staking', None, 'Liquid staking pool address'), + 'min_loan': Setting('liquid-staking', 41000, 'Min loan amount'), + 'max_loan': Setting('liquid-staking', 43000, 'Max loan amount'), + 'max_interest_percent': Setting('liquid-staking', 10, 'Max interest percent'), + 'duplicateSendfile': Setting(None, True, 'Duplicate external to public Liteservers'), + 'sendTelemetry': Setting(None, True, 'Send node telemetry'), + 'telemetryLiteUrl': Setting(None, 'https://telemetry.toncenter.com/report_status', 'Telemetry url'), + 'overlayTelemetryUrl': Setting(None, 'https://telemetry.toncenter.com/report_overlays', 'Overlay telemetry url'), + 'duplicateApi': Setting(None, 'sendTelemetry', 'Duplicate external to Toncenter'), + 'duplicateApiUrl': Setting(None, 'https://[testnet.]toncenter.com/api/v2/sendBoc', 'Toncenter api url for duplicate'), + 'liteclient_timeout': Setting(None, 3, 'Liteclient default timeout'), + 'console_timeout': Setting(None, 3, 'Validator console default timeout'), + 'fift_timeout': Setting(None, 3, 'Fift default timeout'), + 'useDefaultCustomOverlays': Setting(None, True, 'Participate in default custom overlays node eligible to'), + 'defaultCustomOverlaysUrl': Setting(None, 'https://ton-blockchain.github.io/fallback_custom_overlays.json', 'Default custom overlays config url'), +} + + +def get_setting(name: str) -> typing.Optional[Setting]: + return SETTINGS.get(name) + + +def get_mode_settings(name: str): + return {k: v for k, v in SETTINGS.items() if v.mode == name} + diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index a716483d..9f344417 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -181,16 +181,21 @@ def inject_globals(func): def about(local, ton, args): + from modules import get_mode, get_mode_settings if len(args) != 1: color_print("{red}Bad args. Usage:{endc} about ") mode_name = args[0] - mode = ton.get_mode(mode_name) + mode = get_mode(mode_name) if mode is None: color_print(f"{{red}}Mode {mode_name} not found{{endc}}") return + mode_settings = get_mode_settings(mode_name) color_print(f'''{{cyan}}===[ {mode_name} MODE ]==={{cyan}}=''') color_print(f'''Description: {mode.description}''') color_print('Enabled: ' + color_text('{green}yes{endc}' if ton.get_mode_value(mode_name) else '{red}no{endc}')) + print('Settings:', 'no' if len(mode_settings) == 0 else '') + for setting_name, setting in mode_settings.items(): + print(f' {setting_name}: {setting.description}. Default value: {setting.default_value}') #end define @@ -1287,6 +1292,18 @@ def SetSettings(ton, args): color_print(f"{{red}} Error: set {name} ... is deprecated and does not work {{endc}}." f"\nInstead, use {{bold}}enable_mode {mode_name}{{endc}}") return + force = False + if len(args) > 2: + if args[2] == "--force": + force = True + from modules import get_setting + setting = get_setting(name) + if setting is None and not force: + color_print(f"{{red}} Error: setting {name} not found {{endc}}. use flag --force to set it anyway") + if setting.mode is not None: + if not ton.get_mode_value(setting.mode) and not force: + color_print(f"{{red}} Error: mode {setting.mode} is disabled {{endc}}. Use flag --force to set it anyway") + return ton.SetSettings(name, value) color_print("SetSettings - {green}OK{endc}") #end define From 253f34c8201ddfb9fc35e7cbba40f70c2f856ce8 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 12:20:31 +0800 Subject: [PATCH 173/236] bugfix --- modules/validator.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/validator.py b/modules/validator.py index ebceb771..e3569f93 100644 --- a/modules/validator.py +++ b/modules/validator.py @@ -1,8 +1,6 @@ from mypylib.mypylib import color_print from modules.module import MtcModule -from mytoncore.functions import Elections - class ValidatorModule(MtcModule): @@ -20,6 +18,7 @@ def vote_offer(self, args): color_print("VoteOffer - {green}OK{endc}") def vote_election_entry(self, args): + from mytoncore.functions import Elections Elections(self.ton.local, self.ton) color_print("VoteElectionEntry - {green}OK{endc}") From 053e96c8c3cfb82245562ee661ce25bd2e0ce50d Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 14:14:29 +0800 Subject: [PATCH 174/236] about cosmetic bugfix --- modules/__init__.py | 2 +- mytonctrl/mytonctrl.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/__init__.py b/modules/__init__.py index 9c8c381b..a06e0aa5 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -29,7 +29,7 @@ class Setting: SETTINGS = { - 'stake': Setting('validator', False, 'Stake amount'), + 'stake': Setting('validator', None, 'Stake amount'), 'stakePercent': Setting('validator', 99, 'Stake percent if `stake` is null'), 'isSlashing': Setting('validator', None, 'Create complaints to validators'), 'maxFactor': Setting('validator', None, 'Param send to Elector. if null will be taken from 17 config param'), diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 9f344417..4b38dd64 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -190,12 +190,12 @@ def about(local, ton, args): color_print(f"{{red}}Mode {mode_name} not found{{endc}}") return mode_settings = get_mode_settings(mode_name) - color_print(f'''{{cyan}}===[ {mode_name} MODE ]==={{cyan}}=''') + color_print(f'''{{cyan}}===[ {mode_name} MODE ]==={{endc}}''') color_print(f'''Description: {mode.description}''') color_print('Enabled: ' + color_text('{green}yes{endc}' if ton.get_mode_value(mode_name) else '{red}no{endc}')) print('Settings:', 'no' if len(mode_settings) == 0 else '') for setting_name, setting in mode_settings.items(): - print(f' {setting_name}: {setting.description}. Default value: {setting.default_value}') + color_print(f' {{bold}}{setting_name}{{endc}}: {setting.description}.\n Default value: {setting.default_value}') #end define From 1afbcb98801eaceb9dc03890bb5225599be5815b Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 14:27:49 +0800 Subject: [PATCH 175/236] fix set --- mytonctrl/mytonctrl.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 4b38dd64..2bf1efc5 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1299,10 +1299,11 @@ def SetSettings(ton, args): from modules import get_setting setting = get_setting(name) if setting is None and not force: - color_print(f"{{red}} Error: setting {name} not found {{endc}}. use flag --force to set it anyway") - if setting.mode is not None: + color_print(f"{{red}} Error: setting {name} not found.{{endc}} Use flag --force to set it anyway") + return + if setting is not None and setting.mode is not None: if not ton.get_mode_value(setting.mode) and not force: - color_print(f"{{red}} Error: mode {setting.mode} is disabled {{endc}}. Use flag --force to set it anyway") + color_print(f"{{red}} Error: mode {setting.mode} is disabled.{{endc}} Use flag --force to set it anyway") return ton.SetSettings(name, value) color_print("SetSettings - {green}OK{endc}") From ae33e4592f7159e725f32ba747636571422b73fe Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 14:43:06 +0800 Subject: [PATCH 176/236] add status_settings --- mytonctrl/mytonctrl.py | 12 ++++++++++++ mytonctrl/resources/translate.json | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 2bf1efc5..d61b549a 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -70,6 +70,7 @@ def inject_globals(func): console.AddItem("installer", inject_globals(Installer), local.translate("installer_cmd")) console.AddItem("status", inject_globals(PrintStatus), local.translate("status_cmd")) console.AddItem("status_modes", inject_globals(mode_status), local.translate("status_modes_cmd")) + console.AddItem("status_settings", inject_globals(settings_status), local.translate("settings_status_cmd")) console.AddItem("enable_mode", inject_globals(enable_mode), local.translate("enable_mode_cmd")) console.AddItem("disable_mode", inject_globals(disable_mode), local.translate("disable_mode_cmd")) console.AddItem("about", inject_globals(about), local.translate("about_cmd")) @@ -458,6 +459,17 @@ def mode_status(ton, args): #end define +def settings_status(ton, args): + from modules import SETTINGS + color_print(f'''{{cyan}}===[ SETTINGS ]==={{endc}}''') + table = [["Name", "Description", "Mode", "Default value", "Current value"]] + for name, setting in SETTINGS.items(): + current_value = ton.local.db.get(name) + table.append([name, setting.description, setting.mode, setting.default_value, current_value]) + print_table(table) +#end define + + def PrintStatus(local, ton, args): opt = None if len(args) == 1: diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 7a5f7c28..53fb5911 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -19,6 +19,11 @@ "ru": "Показать режимы MTC", "zh_TW": "顯示 MTC 模式" }, + "settings_status_cmd": { + "en": "Show all available settings with their description and values", + "ru": "Показать все доступные настройки с их описанием и значениями", + "zh_TW": "顯示所有可用設定及其描述和值" + }, "about_cmd": { "en": "Mode description", "ru": "Описание режима", From e79e6876c1f281d3c236622ca5b0614b855e504a Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 12 Apr 2024 14:45:07 +0800 Subject: [PATCH 177/236] cosmetic status_settings --- mytonctrl/mytonctrl.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index d61b549a..382b9611 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -461,7 +461,6 @@ def mode_status(ton, args): def settings_status(ton, args): from modules import SETTINGS - color_print(f'''{{cyan}}===[ SETTINGS ]==={{endc}}''') table = [["Name", "Description", "Mode", "Default value", "Current value"]] for name, setting in SETTINGS.items(): current_value = ton.local.db.get(name) From 2736c5750849124c5588c33597bfd444c476a975 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 15 Apr 2024 13:14:39 +0800 Subject: [PATCH 178/236] add disk usage warning --- mytonctrl/mytonctrl.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index adaf8a9c..cd7ccc27 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -242,6 +242,7 @@ def PreUp(local, ton): CheckMytonctrlUpdate(local) check_installer_user() check_vport(local, ton) + warnings(local, ton) # CheckTonUpdate() #end define @@ -454,6 +455,21 @@ def CheckMytonctrlUpdate(local): color_print(local.translate("mytonctrl_update_available")) #end define +def print_warning(local, warning_name: str): + color_print("============================================================================================") + color_print(local.translate(warning_name)) + color_print("============================================================================================") +#end define + +def check_disk_usage(local, ton): + usage = ton.GetDbUsage() + if usage > 90: + print_warning(local, "disk_usage_warning") +#end define + +def warnings(local, ton): + check_disk_usage(local, ton) + def CheckTonUpdate(local): git_path = "/usr/src/ton" result = check_git_update(git_path) From d336201967a6800adae8d32e760e4c97007232e7 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 15 Apr 2024 17:00:00 +0800 Subject: [PATCH 179/236] add 2nd way to get own ip --- mytoninstaller/config.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mytoninstaller/config.py b/mytoninstaller/config.py index 92fa474f..83039853 100644 --- a/mytoninstaller/config.py +++ b/mytoninstaller/config.py @@ -1,5 +1,6 @@ import os import json +import re import subprocess import requests import base64 @@ -118,8 +119,13 @@ def CreateLocalConfig(local, initBlock, localConfigPath=defaultLocalConfigPath): def get_own_ip(): + pat = re.compile(r"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$") requests.packages.urllib3.util.connection.HAS_IPV6 = False ip = requests.get("https://ifconfig.me/ip").text + if not pat.fullmatch(ip): + ip = requests.get("https://ipinfo.io/ip").text + if not pat.fullmatch(ip): + raise Exception('Cannot get own IP address') return ip #end define From 34539fd36efc046674e732f630f4fb0ba91a5500 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 16 Apr 2024 11:05:12 +0800 Subject: [PATCH 180/236] move telemetry to separate file --- mytoncore/functions.py | 151 ++--------------------------------------- mytoncore/telemetry.py | 143 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 149 insertions(+), 145 deletions(-) create mode 100644 mytoncore/telemetry.py diff --git a/mytoncore/functions.py b/mytoncore/functions.py index c7a3d373..f45cb88d 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -10,18 +10,16 @@ import subprocess from mytoncore.mytoncore import MyTonCore -from mytoncore.utils import parse_db_stats from mytoninstaller.config import GetConfig from mypylib.mypylib import ( b2mb, get_timestamp, get_internet_interface_name, get_git_hash, - get_service_pid, get_load_avg, thr_sleep, - Dict ) +from mytoncore.telemetry import * from mytoninstaller.node_args import get_node_args @@ -382,141 +380,6 @@ def Domains(local, ton): # 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 get_db_stats(): - result = { - 'rocksdb': { - 'ok': True, - 'message': '', - 'data': {} - }, - 'celldb': { - 'ok': True, - 'message': '', - 'data': {} - }, - } - rocksdb_stats_path = '/var/ton-work/db/db_stats.txt' - celldb_stats_path = '/var/ton-work/db/celldb/db_stats.txt' - if os.path.exists(rocksdb_stats_path): - try: - result['rocksdb']['data'] = parse_db_stats(rocksdb_stats_path) - except Exception as e: - result['rocksdb']['ok'] = False - result['rocksdb']['message'] = f'failed to fetch db stats: {e}' - else: - result['rocksdb']['ok'] = False - result['rocksdb']['message'] = 'db stats file is not exists' - # end if - - if os.path.exists(celldb_stats_path): - try: - result['celldb']['data'] = parse_db_stats(celldb_stats_path) - except Exception as e: - result['celldb']['ok'] = False - result['celldb']['message'] = f'failed to fetch db stats: {e}' - else: - result['celldb']['ok'] = False - result['celldb']['message'] = 'db stats file is not exists' - # end if - - return result -# end define - - -def get_cpu_name(): - with open('/proc/cpuinfo') as f: - for line in f: - if line.strip(): - if line.rstrip('\n').startswith('model name'): - return line.rstrip('\n').split(':')[1].strip() - return None - - -def is_host_virtual(): - try: - with open('/sys/class/dmi/id/product_name') as f: - product_name = f.read().strip().lower() - if 'virtual' in product_name or 'kvm' in product_name or 'qemu' in product_name or 'vmware' in product_name: - return {'virtual': True, 'product_name': product_name} - return {'virtual': False, 'product_name': product_name} - except FileNotFoundError: - return {'virtual': None, 'product_name': None} - - -def do_beacon_ping(host, count, timeout): - args = ['ping', '-c', str(count), '-W', str(timeout), host] - process = subprocess.run(args, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) - output = process.stdout.decode("utf-8") - avg = output.split('\n')[-2].split('=')[1].split('/')[1] - return float(avg) - - -def get_pings_values(): - return { - 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 5, 10), - 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 5, 10) - } - - -def get_validator_disk_name(): - process = subprocess.run("df -h /var/ton-work/ | sed -n '2 p' | awk '{print $1}'", stdin=subprocess.PIPE, - stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3, shell=True) - output = process.stdout.decode("utf-8") - return output.strip() - - def Telemetry(local, ton): sendTelemetry = local.db.get("sendTelemetry") if sendTelemetry is not True: @@ -540,13 +403,11 @@ def Telemetry(local, ton): data["swap"] = GetSwapInfo() data["uname"] = GetUname() data["vprocess"] = GetValidatorProcessInfo() - data["dbStats"] = get_db_stats() - data["nodeArgs"] = get_node_args() - data["cpuInfo"] = {'cpuName': get_cpu_name(), 'virtual': is_host_virtual()} - data["validatorDiskName"] = get_validator_disk_name() - data["pings"] = get_pings_values() - elections = local.try_function(ton.GetElectionEntries) - complaints = local.try_function(ton.GetComplaints) + data["dbStats"] = local.try_function(get_db_stats) + data["nodeArgs"] = local.try_function(get_node_args) + data["cpuInfo"] = {'cpuName': local.try_function(get_cpu_name), 'virtual': local.try_function(is_host_virtual)} + data["validatorDiskName"] = local.try_function(get_validator_disk_name) + data["pings"] = local.try_function(get_pings_values) # Get git hashes gitHashes = dict() diff --git a/mytoncore/telemetry.py b/mytoncore/telemetry.py new file mode 100644 index 00000000..f02b2eaf --- /dev/null +++ b/mytoncore/telemetry.py @@ -0,0 +1,143 @@ +import os +import subprocess + +import psutil + +from mytoncore.utils import parse_db_stats +from mypylib.mypylib import get_service_pid + + +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 get_db_stats(): + result = { + 'rocksdb': { + 'ok': True, + 'message': '', + 'data': {} + }, + 'celldb': { + 'ok': True, + 'message': '', + 'data': {} + }, + } + rocksdb_stats_path = '/var/ton-work/db/db_stats.txt' + celldb_stats_path = '/var/ton-work/db/celldb/db_stats.txt' + if os.path.exists(rocksdb_stats_path): + try: + result['rocksdb']['data'] = parse_db_stats(rocksdb_stats_path) + except Exception as e: + result['rocksdb']['ok'] = False + result['rocksdb']['message'] = f'failed to fetch db stats: {e}' + else: + result['rocksdb']['ok'] = False + result['rocksdb']['message'] = 'db stats file is not exists' + # end if + + if os.path.exists(celldb_stats_path): + try: + result['celldb']['data'] = parse_db_stats(celldb_stats_path) + except Exception as e: + result['celldb']['ok'] = False + result['celldb']['message'] = f'failed to fetch db stats: {e}' + else: + result['celldb']['ok'] = False + result['celldb']['message'] = 'db stats file is not exists' + # end if + + return result +# end define + + +def get_cpu_name(): + with open('/proc/cpuinfo') as f: + for line in f: + if line.strip(): + if line.rstrip('\n').startswith('model name'): + return line.rstrip('\n').split(':')[1].strip() + return None + + +def is_host_virtual(): + try: + with open('/sys/class/dmi/id/product_name') as f: + product_name = f.read().strip().lower() + if 'virtual' in product_name or 'kvm' in product_name or 'qemu' in product_name or 'vmware' in product_name: + return {'virtual': True, 'product_name': product_name} + return {'virtual': False, 'product_name': product_name} + except FileNotFoundError: + return {'virtual': None, 'product_name': None} + + +def do_beacon_ping(host, count, timeout): + args = ['ping', '-c', str(count), '-W', str(timeout), host] + process = subprocess.run(args, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=timeout) + output = process.stdout.decode("utf-8") + avg = output.split('\n')[-2].split('=')[1].split('/')[1] + return float(avg) + + +def get_pings_values(): + return { + 'beacon-eu-01.toncenter.com': do_beacon_ping('beacon-eu-01.toncenter.com', 5, 10), + 'beacon-apac-01.toncenter.com': do_beacon_ping('beacon-apac-01.toncenter.com', 5, 10) + } + + +def get_validator_disk_name(): + process = subprocess.run("df -h /var/ton-work/ | sed -n '2 p' | awk '{print $1}'", stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3, shell=True) + output = process.stdout.decode("utf-8") + return output.strip() + From 425a5c3a9d446e100a210cff278b57792049bba3 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 18 Apr 2024 12:31:03 +0300 Subject: [PATCH 181/236] add config.id to PrintOffersList --- mytoncore/mytoncore.py | 4 ++-- mytonctrl/mytonctrl.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 97c1318f..727ee922 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2087,8 +2087,8 @@ def GetOffers(self): # Create dict # parser from: https://github.com/ton-blockchain/ton/blob/dab7ee3f9794db5a6d32c895dbc2564f681d9126/crypto/smartcont/config-code.fc#L607 - item = dict() - item["config"] = dict() + item = Dict() + item["config"] = Dict() item["hash"] = hash item["endTime"] = subdata[0] # *expires* item["critFlag"] = subdata[1] # *critical* diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index cd7ccc27..8f209018 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1104,7 +1104,7 @@ def PrintOffersList(ton, args): print(text) else: table = list() - table += [["Hash", "Votes", "W/L", "Approved", "Is passed"]] + table += [["Hash", "Config", "Votes", "W/L", "Approved", "Is passed"]] for item in data: hash = item.get("hash") votedValidators = len(item.get("votedValidators")) @@ -1120,7 +1120,7 @@ def PrintOffersList(ton, args): isPassed = bcolors.green_text("true") if isPassed == False: isPassed = bcolors.red_text("false") - table += [[hash, votedValidators, wl, approvedPercent_text, isPassed]] + table += [[hash, item.config.id, votedValidators, wl, approvedPercent_text, isPassed]] print_table(table) #end define From ab9d500edd64bc6fbcaef5cef07c54fd43423279 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Thu, 18 Apr 2024 14:35:59 +0300 Subject: [PATCH 182/236] update validator_status --- mytoncore/liteclient.py | 5 ++-- mytoncore/mytoncore.py | 48 +++++++++++++++++------------- mytonctrl/mytonctrl.py | 19 ++++++------ mytonctrl/resources/translate.json | 5 ++++ 4 files changed, 44 insertions(+), 33 deletions(-) diff --git a/mytoncore/liteclient.py b/mytoncore/liteclient.py index 8a7a25df..67f4ed9f 100644 --- a/mytoncore/liteclient.py +++ b/mytoncore/liteclient.py @@ -17,13 +17,12 @@ def Run(self, cmd, **kwargs): 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") + validator_status = self.ton.GetValidatorStatus() 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: + elif useLocalLiteServer and self.pubkeyPath and validator_status.out_of_sync and validator_status.out_of_sync < 20: args = [self.appPath, "--addr", self.addr, "--pub", self.pubkeyPath, "--verbosity", "0", "--cmd", cmd] else: liteServers = self.local.db.get("liteServers") diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 727ee922..9cd98d64 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -810,42 +810,48 @@ def GetShardsNumber(self, block=None): def GetValidatorStatus(self): # Get buffer - bname = "validatorStatus" + bname = "validator_status" buff = self.GetFunctionBuffer(bname) if buff: return buff #end if self.local.add_log("start GetValidatorStatus function", "debug") - validatorStatus = dict() + status = Dict() try: - validatorStatus["isWorking"] = True + # Parse + status.is_working = True result = self.validatorConsole.Run("getstats") - validatorStatus["unixtime"] = int(parse(result, "unixtime", '\n')) - validatorStatus["masterchainblocktime"] = int(parse(result, "masterchainblocktime", '\n')) - validatorStatus["stateserializermasterchainseqno"] = int(parse(result, "stateserializermasterchainseqno", '\n')) - validatorStatus["shardclientmasterchainseqno"] = int(parse(result, "shardclientmasterchainseqno", '\n')) + status.unixtime = int(parse(result, "unixtime", '\n')) + status.masterchainblocktime = int(parse(result, "masterchainblocktime", '\n')) + status.stateserializermasterchainseqno = int(parse(result, "stateserializermasterchainseqno", '\n')) + status.shardclientmasterchainseqno = int(parse(result, "shardclientmasterchainseqno", '\n')) buff = parse(result, "masterchainblock", '\n') - validatorStatus["masterchainblock"] = self.GVS_GetItemFromBuff(buff) + status.masterchainblock = self.GVS_GetItemFromBuff(buff) buff = parse(result, "gcmasterchainblock", '\n') - validatorStatus["gcmasterchainblock"] = self.GVS_GetItemFromBuff(buff) + status.gcmasterchainblock = self.GVS_GetItemFromBuff(buff) buff = parse(result, "keymasterchainblock", '\n') - validatorStatus["keymasterchainblock"] = self.GVS_GetItemFromBuff(buff) + status.keymasterchainblock = self.GVS_GetItemFromBuff(buff) buff = parse(result, "rotatemasterchainblock", '\n') - validatorStatus["rotatemasterchainblock"] = self.GVS_GetItemFromBuff(buff) - validatorStatus["transNum"] = self.local.buffer.get("transNum", -1) - validatorStatus["blocksNum"] = self.local.buffer.get("blocksNum", -1) - validatorStatus["masterBlocksNum"] = self.local.buffer.get("masterBlocksNum", -1) + status.rotatemasterchainblock = self.GVS_GetItemFromBuff(buff) + # Calculate + status.masterchain_out_of_sync = status.unixtime - status.masterchainblocktime + status.shardchain_out_of_sync = status.masterchainblock - status.shardclientmasterchainseqno + status.masterchain_out_of_ser = status.masterchainblock - status.stateserializermasterchainseqno + status.out_of_sync = status.masterchain_out_of_sync if status.masterchain_out_of_sync > status.shardchain_out_of_sync else status.shardchain_out_of_sync + status.out_of_ser = status.masterchain_out_of_ser except Exception as ex: self.local.add_log(f"GetValidatorStatus warning: {ex}", "warning") - validatorStatus["isWorking"] = False - validatorStatus["unixtime"] = get_timestamp() - validatorStatus["masterchainblocktime"] = 0 - validatorStatus["outOfSync"] = validatorStatus["unixtime"] - validatorStatus["masterchainblocktime"] + status.is_working = False + #end try + + # old vars + status.outOfSync = status.out_of_sync + status.isWorking = status.is_working # Set buffer - self.SetFunctionBuffer(bname, validatorStatus) - return validatorStatus + self.SetFunctionBuffer(bname, status) + return status #end define def GVS_GetItemFromBuff(self, buff): @@ -2349,12 +2355,12 @@ def VoteOffer(self, offerHash): if validatorIndex in offer.get("votedValidators"): self.local.add_log("Proposal already has been voted", "debug") return + self.add_save_offer(offer) var1 = self.CreateConfigProposalRequest(offerHash, validatorIndex) validatorSignature = self.GetValidatorSignature(validatorKey, var1) resultFilePath = self.SignProposalVoteRequestWithValidator(offerHash, validatorIndex, validatorPubkey_b64, validatorSignature) resultFilePath = self.SignBocWithWallet(wallet, resultFilePath, fullConfigAddr, 1.5) self.SendFile(resultFilePath, wallet) - self.add_save_offer(offer) #end define def VoteComplaint(self, electionId, complaintHash): diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 8f209018..5cbcdcb7 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -597,7 +597,7 @@ def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shar print() #end define -def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg): +def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg): if validatorWallet is None: return walletAddr = validatorWallet.addrB64 @@ -610,7 +610,6 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid netLoad1 = netLoadAvg[0] netLoad5 = netLoadAvg[1] netLoad15 = netLoadAvg[2] - validatorOutOfSync = validatorStatus.get("outOfSync") validatorIndex_text = GetColorInt(validatorIndex, 0, logic="more") validatorIndex_text = local.translate("local_status_validator_index").format(validatorIndex_text) @@ -671,11 +670,12 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid validatorUptime = get_service_uptime("validator") mytoncoreUptime_text = bcolors.green_text(time2human(mytoncoreUptime)) validatorUptime_text = bcolors.green_text(time2human(validatorUptime)) - mytoncoreStatus = GetColorStatus(mytoncoreStatus_bool) - validatorStatus = GetColorStatus(validatorStatus_bool) - mytoncoreStatus_text = local.translate("local_status_mytoncore_status").format(mytoncoreStatus, mytoncoreUptime_text) - validatorStatus_text = local.translate("local_status_validator_status").format(validatorStatus, validatorUptime_text) - validatorOutOfSync_text = local.translate("local_status_validator_out_of_sync").format(GetColorInt(validatorOutOfSync, 20, logic="less", ending=" s")) + mytoncoreStatus_color = GetColorStatus(mytoncoreStatus_bool) + validatorStatus_color = GetColorStatus(validatorStatus_bool) + mytoncoreStatus_text = local.translate("local_status_mytoncore_status").format(mytoncoreStatus_color, mytoncoreUptime_text) + validatorStatus_text = local.translate("local_status_validator_status").format(validatorStatus_color, validatorUptime_text) + validator_out_of_sync_text = local.translate("local_status_validator_out_of_sync").format(GetColorInt(validator_status.out_of_sync, 20, logic="less", ending=" s")) + validator_out_of_ser_text = local.translate("local_status_validator_out_of_ser").format(GetColorInt(validator_status.out_of_ser, 20, logic="less", ending=" blocks")) dbSize_text = GetColorInt(dbSize, 1000, logic="less", ending=" Gb") dbUsage_text = GetColorInt(dbUsage, 80, logic="less", ending="%") dbStatus_text = local.translate("local_status_db").format(dbSize_text, dbUsage_text) @@ -708,7 +708,8 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid print(disksLoad_text) print(mytoncoreStatus_text) print(validatorStatus_text) - print(validatorOutOfSync_text) + print(validator_out_of_sync_text) + print(validator_out_of_ser_text) print(dbStatus_text) print(mtcVersion_text) print(validatorVersion_text) @@ -717,7 +718,7 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid def GetColorInt(data, border, logic, ending=None): if data is None: - result = bcolors.green_text("n/a") + result = "n/a" elif logic == "more": if data >= border: result = bcolors.green_text(data, ending) diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 53fb5911..4c41a424 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -324,6 +324,11 @@ "ru": "Рассинхронизация локального валидатора: {0}", "zh_TW": "本地驗證者不同步: {0}" }, + "local_status_validator_out_of_ser": { + "en": "Local validator out of ser: {0}", + "ru": "Рассериализация локального валидатора: {0}", + "zh_TW": "本地驗證者不同步: {0}" + }, "local_status_db": { "en": "Local validator database size: {0}, {1}", "ru": "Размер БД локального валидатора: {0}, {1}", From e0076983b70367a06c55056e185c0802fe489331 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 19 Apr 2024 11:16:21 +0400 Subject: [PATCH 183/236] add thread to save past events --- mytoncore/functions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index f45cb88d..9e9f4d05 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -506,6 +506,11 @@ def Slashing(local, ton): # end define +def save_past_events(local, ton): + local.try_function(ton.GetElectionEntries) + local.try_function(ton.GetComplaints) + + def ScanLiteServers(local, ton): # Считать список серверов filePath = ton.liteClient.configPath @@ -540,6 +545,7 @@ def General(local): 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(save_past_events, sec=300, args=(local, ton, )) t = 600 if ton.GetNetworkName() != 'mainnet': From d9176c3bce8150e102d70d743f00fc0ee6cd53b8 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 19 Apr 2024 11:22:56 +0400 Subject: [PATCH 184/236] change exception to log in check_installer_user --- mytonctrl/mytonctrl.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index cd7ccc27..03a44284 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -223,7 +223,7 @@ def about(local, ton, args): #end define -def check_installer_user(): +def check_installer_user(local): args = ["whoami"] process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) username = process.stdout.decode("utf-8").strip() @@ -234,13 +234,13 @@ def check_installer_user(): actual_user = output.split('\n')[1].split()[2] if username != actual_user: - raise Exception(f'mytonctrl was installed by another user. Probably you need to launch mtc with `{actual_user}` user.') + local.add_log(f'mytonctrl was installed by another user. Probably you need to launch mtc with `{actual_user}` user.', 'error') #end define def PreUp(local, ton): CheckMytonctrlUpdate(local) - check_installer_user() + check_installer_user(local) check_vport(local, ton) warnings(local, ton) # CheckTonUpdate() From d2c7a791602e1d303a72e423a3f447ff40d0b358 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 23 Apr 2024 12:24:16 +0400 Subject: [PATCH 185/236] add checking adnl connection --- modules/__init__.py | 1 + mytoncore/mytoncore.py | 37 +++++++++++++++++++++++++++++++++++++ mytonctrl/mytonctrl.py | 1 + 3 files changed, 39 insertions(+) diff --git a/modules/__init__.py b/modules/__init__.py index a06e0aa5..d7e3cc7d 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -44,6 +44,7 @@ class Setting: 'overlayTelemetryUrl': Setting(None, 'https://telemetry.toncenter.com/report_overlays', 'Overlay telemetry url'), 'duplicateApi': Setting(None, 'sendTelemetry', 'Duplicate external to Toncenter'), 'duplicateApiUrl': Setting(None, 'https://[testnet.]toncenter.com/api/v2/sendBoc', 'Toncenter api url for duplicate'), + 'checkAdnl': Setting(None, 'sendTelemetry', 'Check local udp port and adnl connection'), 'liteclient_timeout': Setting(None, 3, 'Liteclient default timeout'), 'console_timeout': Setting(None, 3, 'Validator console default timeout'), 'fift_timeout': Setting(None, 3, 'Fift default timeout'), diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 9cd98d64..a11a6578 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2707,6 +2707,43 @@ def GetDbSize(self, exceptions="log"): return result #end define + def check_adnl(self): + telemetry = self.local.db.get("sendTelemetry", False) + check_adnl = self.local.db.get("checkAdnl", telemetry) + if not check_adnl: + return + url = 'http://45.129.96.53/adnl_check' + try: + data = self.get_local_adnl_data() + response = requests.post(url, json=data, timeout=3).json() + except Exception as e: + self.local.add_log(f'Failed to check adnl connection: {type(e)}: {e}') + return False + result = response.json().get("ok") + if not result: + self.local.add_log(f'Failed to check adnl connection to local node: {response.get("message")}', 'error') + return result + #end define + + def get_local_adnl_data(self): + + def int2ip(dec): + import socket + return socket.inet_ntoa(struct.pack("!i", dec)) + + vconfig = self.GetValidatorConfig() + + data = {"ip": int2ip(vconfig["addrs"][0]["ip"]), "port": vconfig["addrs"][0]["port"]} + + dht_id = vconfig["dht"][0]["id"] + dht_id_hex = base64.b64decode(dht_id).hex().upper() + + result = self.validatorConsole.Run(f"exportpub {dht_id_hex}") + pubkey = parse(result, "got public key: ", "\n") + data["pubkey"] = base64.b64encode(base64.b64decode(pubkey)[4:]) + return data + #end define + def Result2List(self, text): buff = parse(text, "result:", "\n") if buff is None or "error" in buff: diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 216ac25f..882d4e4c 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -242,6 +242,7 @@ def PreUp(local, ton): CheckMytonctrlUpdate(local) check_installer_user(local) check_vport(local, ton) + ton.check_adnl() warnings(local, ton) # CheckTonUpdate() #end define From e5d00f3e6675f0ed7157cc2e4cbb799efe6a8216 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 23 Apr 2024 12:30:09 +0400 Subject: [PATCH 186/236] bugfix bugfix bugfix --- mytoncore/mytoncore.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index a11a6578..3397ee97 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2715,11 +2715,11 @@ def check_adnl(self): url = 'http://45.129.96.53/adnl_check' try: data = self.get_local_adnl_data() - response = requests.post(url, json=data, timeout=3).json() + response = requests.post(url, json=data, timeout=5).json() except Exception as e: - self.local.add_log(f'Failed to check adnl connection: {type(e)}: {e}') + self.local.add_log(f'Failed to check adnl connection: {type(e)}: {e}', 'error') return False - result = response.json().get("ok") + result = response.get("ok") if not result: self.local.add_log(f'Failed to check adnl connection to local node: {response.get("message")}', 'error') return result @@ -2733,14 +2733,14 @@ def int2ip(dec): vconfig = self.GetValidatorConfig() - data = {"ip": int2ip(vconfig["addrs"][0]["ip"]), "port": vconfig["addrs"][0]["port"]} + data = {"host": int2ip(vconfig["addrs"][0]["ip"]), "port": vconfig["addrs"][0]["port"]} dht_id = vconfig["dht"][0]["id"] dht_id_hex = base64.b64decode(dht_id).hex().upper() result = self.validatorConsole.Run(f"exportpub {dht_id_hex}") pubkey = parse(result, "got public key: ", "\n") - data["pubkey"] = base64.b64encode(base64.b64decode(pubkey)[4:]) + data["pubkey"] = base64.b64encode(base64.b64decode(pubkey)[4:]).decode() return data #end define From a83696fa0809fc4148f723081149a5e9bc09849a Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 3 May 2024 19:26:48 +0300 Subject: [PATCH 187/236] not display unnecessary data --- mytonctrl/mytonctrl.py | 117 ++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 882d4e4c..f5a72d12 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -186,7 +186,6 @@ def inject_globals(func): #end define - def activate_ton_storage_provider(local, ton, args): wallet_name = "provider_wallet_001" wallet = ton.GetLocalWallet(wallet_name) @@ -304,7 +303,7 @@ def fix_git_config(git_path: str): subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) else: raise Exception(f'Failed to check git status: {err}') - +#end define def check_git(input_args, default_repo, text): src_dir = "/usr/src" @@ -341,7 +340,7 @@ def check_git(input_args, default_repo, text): need_branch = local_branch check_branch_exists(need_author, need_repo, need_branch) return need_author, need_repo, need_branch - +#end define def check_branch_exists(author, repo, branch): url = f"https://github.com/{author}/{repo}.git" @@ -350,7 +349,7 @@ def check_branch_exists(author, repo, branch): output = process.stdout.decode("utf-8") if branch not in output: raise Exception(f"Branch {branch} not found in {url}") - +#end define def Update(local, args): repo = "mytonctrl" @@ -399,7 +398,7 @@ def Upgrade(ton, args): else: text = "Upgrade - {red}Error{endc}" color_print(text) - +#end define def rollback_to_mtc1(local, ton, args): color_print("{red}Warning: this is dangerous, please make sure you've backed up mytoncore's db.{endc}") @@ -418,7 +417,7 @@ def rollback_to_mtc1(local, ton, args): run_args = ["bash", rollback_script_path] run_as_root(run_args) local.exit() - +#end define def cleanup_validator_db(ton, args): cleanup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/cleanup.sh') @@ -470,6 +469,7 @@ def check_disk_usage(local, ton): def warnings(local, ton): check_disk_usage(local, ton) +#end define def CheckTonUpdate(local): git_path = "/usr/src/ton" @@ -513,49 +513,67 @@ def PrintStatus(local, ton, args): opt = None if len(args) == 1: opt = args[0] - adnlAddr = ton.GetAdnlAddr() - rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() - config34 = ton.GetConfig34() - config36 = ton.GetConfig36() - totalValidators = config34["totalValidators"] + + # Local status + validator_status = ton.GetValidatorStatus() + vconfig = self.GetValidatorConfig() + adnl_addr = ton.GetAdnlAddr() + validator_index = None onlineValidators = None - validatorEfficiency = None - if opt != "fast": - onlineValidators = ton.GetOnlineValidators() - validatorEfficiency = ton.GetValidatorEfficiency() - if onlineValidators: - onlineValidators = len(onlineValidators) - oldStartWorkTime = config36.get("startWorkTime") - if oldStartWorkTime is None: - oldStartWorkTime = config34.get("startWorkTime") - shardsNumber = ton.GetShardsNumber() - validatorStatus = ton.GetValidatorStatus() - config15 = ton.GetConfig15() - config17 = ton.GetConfig17() - fullConfigAddr = ton.GetFullConfigAddr() - fullElectorAddr = ton.GetFullElectorAddr() - startWorkTime = ton.GetActiveElectionId(fullElectorAddr) - validatorIndex = ton.GetValidatorIndex() - validatorWallet = ton.GetValidatorWallet() - dbSize = ton.GetDbSize() - dbUsage = ton.GetDbUsage() - memoryInfo = GetMemoryInfo() - swapInfo = GetSwapInfo() - offersNumber = ton.GetOffersNumber() - complaintsNumber = ton.GetComplaintsNumber() + validator_efficiency = None + validator_wallet = ton.GetValidatorWallet() + validator_account = Dict() + db_size = ton.GetDbSize() + db_usage = ton.GetDbUsage() + memory_info = GetMemoryInfo() + swap_info = GetSwapInfo() statistics = ton.GetSettings("statistics") - tpsAvg = ton.GetStatistics("tpsAvg", statistics) - netLoadAvg = ton.GetStatistics("netLoadAvg", statistics) - disksLoadAvg = ton.GetStatistics("disksLoadAvg", statistics) - disksLoadPercentAvg = ton.GetStatistics("disksLoadPercentAvg", statistics) - if validatorWallet is not None: - validatorAccount = ton.GetAccount(validatorWallet.addrB64) - else: - validatorAccount = None - PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) - PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validatorStatus, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg) - PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) - PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) + net_load_avg = ton.GetStatistics("netLoadAvg", statistics) + disks_load_avg = ton.GetStatistics("disksLoadAvg", statistics) + disks_load_percent_avg = ton.GetStatistics("disksLoadPercentAvg", statistics) + + #is_validator = len(vconfig.validators) > 0 + all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 + if all_status: + rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() + config34 = ton.GetConfig34() + config36 = ton.GetConfig36() + totalValidators = config34["totalValidators"] + + if opt != "fast": + onlineValidators = ton.GetOnlineValidators() + validator_efficiency = ton.GetValidatorEfficiency() + if onlineValidators: + onlineValidators = len(onlineValidators) + + oldStartWorkTime = config36.get("startWorkTime") + if oldStartWorkTime is None: + oldStartWorkTime = config34.get("startWorkTime") + shardsNumber = ton.GetShardsNumber() + + config15 = ton.GetConfig15() + config17 = ton.GetConfig17() + fullConfigAddr = ton.GetFullConfigAddr() + fullElectorAddr = ton.GetFullElectorAddr() + startWorkTime = ton.GetActiveElectionId(fullElectorAddr) + validator_index = ton.GetValidatorIndex() + + offersNumber = ton.GetOffersNumber() + complaintsNumber = ton.GetComplaintsNumber() + + tpsAvg = ton.GetStatistics("tpsAvg", statistics) + + if validator_wallet is not None: + validator_account = ton.GetAccount(validator_wallet.addrB64) + #end if + + if all_status: + PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) + PrintLocalStatus(local, adnl_addr, validator_index, validator_efficiency, validator_wallet, validator_account, validator_status, + db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg) + if all_status: + PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) + PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) #end define def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): @@ -1371,7 +1389,7 @@ def enable_mode(local, ton, args): ton.enable_mode(name) color_print("enable_mode - {green}OK{endc}") local.exit() - +#end define def disable_mode(local, ton, args): try: @@ -1382,7 +1400,7 @@ def disable_mode(local, ton, args): ton.disable_mode(name) color_print("disable_mode - {green}OK{endc}") local.exit() - +#end define def Xrestart(inputArgs): if len(inputArgs) < 2: @@ -1436,6 +1454,7 @@ def GetPoolData(ton, args): pool_addr = pool.addrB64 pool_data = ton.GetPoolData(pool_addr) print(json.dumps(pool_data, indent=4)) +#end define ### Start of the program From 8047e59b86dba88ff018180bf0fe98ce5fb508df Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sat, 4 May 2024 17:13:28 +0300 Subject: [PATCH 188/236] bugfix --- mytonctrl/mytonctrl.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index f5a72d12..c358fefa 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -516,7 +516,6 @@ def PrintStatus(local, ton, args): # Local status validator_status = ton.GetValidatorStatus() - vconfig = self.GetValidatorConfig() adnl_addr = ton.GetAdnlAddr() validator_index = None onlineValidators = None @@ -532,7 +531,6 @@ def PrintStatus(local, ton, args): disks_load_avg = ton.GetStatistics("disksLoadAvg", statistics) disks_load_percent_avg = ton.GetStatistics("disksLoadPercentAvg", statistics) - #is_validator = len(vconfig.validators) > 0 all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 if all_status: rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() From a82ad848d6f9ba4ae69448f620f64e1e067a1854 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Wed, 8 May 2024 00:29:13 +0300 Subject: [PATCH 189/236] add network name into status --- mytoncore/mytoncore.py | 4 ++++ mytonctrl/mytonctrl.py | 25 +++++++++++++++---------- mytonctrl/resources/translate.json | 5 +++++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 3397ee97..3a30ab41 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1208,6 +1208,8 @@ def SignBocWithWallet(self, wallet, boc_path, dest, coins, **kwargs): elif "v3" in wallet.version: fift_script = "wallet-v3.fif" args = [fift_script, wallet.path, dest, subwallet, seqno, coins, boc_mode, boc_path, result_file_path] + else: + raise Exception(f"SignBocWithWallet error: Wallet version '{wallet.version}' is not supported") if flags: args += flags result = self.fift.Run(args) @@ -1912,6 +1914,8 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): elif "v3" in wallet.version: fiftScript = "wallet-v3.fif" args = [fiftScript, wallet.path, dest, subwallet, seqno, coins, "-m", mode, resultFilePath] + else: + raise Exception(f"MoveCoins error: Wallet version '{wallet.version}' is not supported") if flags: args += flags result = self.fift.Run(args) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index c358fefa..e8b52bac 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -533,6 +533,7 @@ def PrintStatus(local, ton, args): all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 if all_status: + network_name = ton.GetNetworkName() rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() config34 = ton.GetConfig34() config36 = ton.GetConfig36() @@ -566,7 +567,7 @@ def PrintStatus(local, ton, args): #end if if all_status: - PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) + PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) PrintLocalStatus(local, adnl_addr, validator_index, validator_efficiency, validator_wallet, validator_account, validator_status, db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg) if all_status: @@ -574,19 +575,22 @@ def PrintStatus(local, ton, args): PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) #end define -def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): - tps1 = tpsAvg[0] - tps5 = tpsAvg[1] - tps15 = tpsAvg[2] +def PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg): + #tps1 = tpsAvg[0] + #tps5 = tpsAvg[1] + #tps15 = tpsAvg[2] allValidators = totalValidators newOffers = offersNumber.get("new") allOffers = offersNumber.get("all") newComplaints = complaintsNumber.get("new") allComplaints = complaintsNumber.get("all") - tps1_text = bcolors.green_text(tps1) - tps5_text = bcolors.green_text(tps5) - tps15_text = bcolors.green_text(tps15) - tps_text = local.translate("ton_status_tps").format(tps1_text, tps5_text, tps15_text) + #tps1_text = bcolors.green_text(tps1) + #tps5_text = bcolors.green_text(tps5) + #tps15_text = bcolors.green_text(tps15) + + color_network_name = bcolors.green_text(network_name) if network_name == "mainnet" else bcolors.yellow_text(network_name) + network_name_text = local.translate("ton_status_network_name").format(color_network_name) + #tps_text = local.translate("ton_status_tps").format(tps1_text, tps5_text, tps15_text) onlineValidators_text = GetColorInt(onlineValidators, border=allValidators*2/3, logic="more") allValidators_text = bcolors.yellow_text(allValidators) validators_text = local.translate("ton_status_validators").format(onlineValidators_text, allValidators_text) @@ -605,7 +609,8 @@ def PrintTonStatus(local, startWorkTime, totalValidators, onlineValidators, shar election_text = local.translate("ton_status_election").format(election_text) color_print(local.translate("ton_status_head")) - print(tps_text) + print(network_name_text) + #print(tps_text) print(validators_text) print(shards_text) print(offers_text) diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 4c41a424..a4a59c47 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -224,6 +224,11 @@ "ru": "{cyan}===[ Статус сети TON ]==={endc}", "zh_TW": "{cyan}===[ TON 網路狀態 ]==={endc}" }, + "ton_status_network_name": { + "en": "Network name: {0}", + "ru": "Название сети: {0}", + "zh_TW": "網路名字: {0}" + }, "ton_status_tps": { "en": "Transactions per second (TPS): {0}, {1}, {2}", "ru": "Транзакций в секунду (TPS): {0}, {1}, {2}", From 48e548673cd0ed5fd54c30386d93809a70dfd95d Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 13 May 2024 15:53:01 +0300 Subject: [PATCH 190/236] use jemalloc --- mytonctrl/scripts/upgrade.sh | 4 ++-- scripts/ton_installer.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mytonctrl/scripts/upgrade.sh b/mytonctrl/scripts/upgrade.sh index c7580ef8..7814f0aa 100644 --- a/mytonctrl/scripts/upgrade.sh +++ b/mytonctrl/scripts/upgrade.sh @@ -29,7 +29,7 @@ COLOR='\033[92m' ENDC='\033[0m' # Установить дополнительные зависимости -apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio rocksdb-tools liblz4-dev +apt-get install -y libsecp256k1-dev libsodium-dev ninja-build fio rocksdb-tools liblz4-dev libjemalloc-dev # bugfix if the files are in the wrong place wget "https://ton-blockchain.github.io/global.config.json" -O global.config.json @@ -76,7 +76,7 @@ rm -rf .ninja_* memory=$(cat /proc/meminfo | grep MemAvailable | awk '{print $2}') cpuNumber=$(cat /proc/cpuinfo | grep "processor" | wc -l) -cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a +cmake -DCMAKE_BUILD_TYPE=Release ${srcdir}/${repo} -GNinja -DTON_USE_JEMALLOC=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a ninja -j ${cpuNumber} fift validator-engine lite-client pow-miner validator-engine-console generate-random-id dht-server func tonlibjson rldp-http-proxy systemctl restart validator diff --git a/scripts/ton_installer.sh b/scripts/ton_installer.sh index 81feecbd..500a92f3 100644 --- a/scripts/ton_installer.sh +++ b/scripts/ton_installer.sh @@ -50,7 +50,7 @@ if [ "$OSTYPE" == "linux-gnu" ]; then elif [ -f /etc/debian_version ]; then echo "Ubuntu/Debian Linux detected." apt-get update - apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev liblz4-dev + apt-get install -y build-essential curl git cmake clang libgflags-dev zlib1g-dev libssl-dev libreadline-dev libmicrohttpd-dev pkg-config libgsl-dev python3 python3-dev python3-pip libsecp256k1-dev libsodium-dev liblz4-dev libjemalloc-dev # Install ninja apt-get install -y ninja-build @@ -131,7 +131,7 @@ if [[ "$OSTYPE" =~ darwin.* ]]; then cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton fi else - cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a + cmake -DCMAKE_BUILD_TYPE=Release $SOURCES_DIR/ton -GNinja -DTON_USE_JEMALLOC=ON -DOPENSSL_FOUND=1 -DOPENSSL_INCLUDE_DIR=$opensslPath/include -DOPENSSL_CRYPTO_LIBRARY=$opensslPath/libcrypto.a fi # Расчитываем количество процессоров для сборки From 566e4a692fe11207b3e45e93eae2a0e5fc889b9e Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 15 May 2024 13:17:42 +0700 Subject: [PATCH 191/236] add liteserver mode --- modules/__init__.py | 2 ++ modules/liteserver.py | 26 ++++++++++++++++++++++++++ mytoncore/mytoncore.py | 17 +++++++++++++++++ mytonctrl/mytonctrl.py | 2 +- 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 modules/liteserver.py diff --git a/modules/__init__.py b/modules/__init__.py index d7e3cc7d..5a44fa3e 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -7,6 +7,7 @@ from modules.single_pool import SingleNominatorModule from modules.validator import ValidatorModule from modules.controller import ControllerModule +from modules.liteserver import LiteserverModule MODES = { @@ -14,6 +15,7 @@ 'nominator-pool': NominatorPoolModule, 'single-nominator': SingleNominatorModule, 'liquid-staking': ControllerModule, + 'liteserver': LiteserverModule } diff --git a/modules/liteserver.py b/modules/liteserver.py new file mode 100644 index 00000000..212fc167 --- /dev/null +++ b/modules/liteserver.py @@ -0,0 +1,26 @@ +import psutil + +from modules.module import MtcModule +from mytoninstaller.mytoninstaller import set_node_argument +from mytoninstaller.node_args import get_node_args + + +class LiteserverModule(MtcModule): + + description = 'For liteserver usage only - can\'t be used with validator.' + default_value = False + + def enable(self): + set_node_argument(self.local, ["--celldb-no-preload-all"]) + data = psutil.virtual_memory() + ram = round(data.total / 2**30, 2) + if ram < 100: + set_node_argument(self.local, ["--celldb-cache-size", "1073741824"]) + + def disable(self): + set_node_argument(self.local, ["--celldb-no-preload-all", "-d"]) + if get_node_args()['--celldb-cache-size']: + set_node_argument(self.local, ["--celldb-cache-size", "-d"]) + + def add_console_commands(self, console): + ... diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 3a30ab41..16a2566b 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3261,9 +3261,21 @@ def get_modes(self): current_modes[name] = mode.default_value # assign default mode value return current_modes + def check_enable_mode(self, name): + if name == 'liteserver': + if self.using_validator(): + raise Exception(f'Cannot enable liteserver mode while validator mode is enabled. ' + f'Use `disable_mode validator` first.') + MODES['liteserver'].enable() + if name == 'validator': + if self.using_liteserver(): + raise Exception(f'Cannot enable validator mode while liteserver mode is enabled. ' + f'Use `disable_mode liteserver` first.') + def enable_mode(self, name): if name not in MODES: raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') + self.check_enable_mode(name) current_modes = self.get_modes() current_modes[name] = True self.local.save() @@ -3272,6 +3284,8 @@ def disable_mode(self, name): current_modes = self.get_modes() if name not in current_modes: raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') + if name == 'liteserver': + MODES['liteserver'].disable() current_modes[name] = False self.local.save() @@ -3296,6 +3310,9 @@ def using_pool(self) -> bool: def using_validator(self): return self.get_mode_value('validator') + def using_liteserver(self): + return self.get_mode_value('liteserver') + def Tlb2Json(self, text): # Заменить скобки start = 0 diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index e8b52bac..43ace71c 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -141,7 +141,7 @@ def inject_globals(func): module = NominatorPoolModule(ton, local) module.add_console_commands(console) - if ton.get_mode_value('single-nominator'): + if ton.using_single_nominator(): from modules.single_pool import SingleNominatorModule module = SingleNominatorModule(ton, local) module.add_console_commands(console) From 540e5f8971350f7ff2b0be9950762f15044f609e Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 15 May 2024 13:32:10 +0700 Subject: [PATCH 192/236] bugfix bugfix --- modules/liteserver.py | 2 +- mytoncore/mytoncore.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/liteserver.py b/modules/liteserver.py index 212fc167..63833ea8 100644 --- a/modules/liteserver.py +++ b/modules/liteserver.py @@ -13,7 +13,7 @@ class LiteserverModule(MtcModule): def enable(self): set_node_argument(self.local, ["--celldb-no-preload-all"]) data = psutil.virtual_memory() - ram = round(data.total / 2**30, 2) + ram = data.total / 2**30 if ram < 100: set_node_argument(self.local, ["--celldb-cache-size", "1073741824"]) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 16a2566b..f230c381 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3266,7 +3266,7 @@ def check_enable_mode(self, name): if self.using_validator(): raise Exception(f'Cannot enable liteserver mode while validator mode is enabled. ' f'Use `disable_mode validator` first.') - MODES['liteserver'].enable() + MODES['liteserver'](self, self.local).enable() if name == 'validator': if self.using_liteserver(): raise Exception(f'Cannot enable validator mode while liteserver mode is enabled. ' @@ -3285,7 +3285,7 @@ def disable_mode(self, name): if name not in current_modes: raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') if name == 'liteserver': - MODES['liteserver'].disable() + MODES['liteserver'](self, self.local).disable() current_modes[name] = False self.local.save() From c9f6a48e1ae8e4f54d1f1e8df203c4403fef2bf7 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 15 May 2024 16:51:20 +0700 Subject: [PATCH 193/236] add installation with liteserver bugfix --- mytoncore/functions.py | 9 +++++++++ mytoninstaller/mytoninstaller.py | 8 +++++++- mytoninstaller/settings.py | 6 ++++++ scripts/install.sh | 20 ++++++++++++-------- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 9e9f4d05..12e36ba3 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -54,6 +54,8 @@ def Event(local, event_name): ValidatorDownEvent(local) elif event_name == "enable_ton_storage_provider": enable_ton_storage_provider_event(local) + elif event_name == "enable_liteserver_mode": + enable_liteserver_mode(local) local.exit() # end define @@ -90,6 +92,13 @@ def enable_ton_storage_provider_event(local): #end define +def enable_liteserver_mode(local): + ton = MyTonCore(local) + ton.disable_mode('validator') + ton.enable_mode('liteserver') +#end define + + def Elections(local, ton): use_pool = ton.using_pool() use_liquid_staking = ton.using_liquid_staking() diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index 56daf47e..d8c51cca 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -29,7 +29,8 @@ CreateSymlinks, enable_ls_proxy, enable_ton_storage, - enable_ton_storage_provider + enable_ton_storage_provider, + EnableMode ) from mytoninstaller.config import ( CreateLocalConfig, @@ -255,6 +256,10 @@ def General(local): mx = sys.argv.index("--dump") dump = sys.argv[mx+1] local.buffer.dump = str2bool(dump) + if "-m" in sys.argv: + mx = sys.argv.index("-m") + mode = sys.argv[mx+1] + local.buffer.mode = mode #end if FirstMytoncoreSettings(local) @@ -264,6 +269,7 @@ def General(local): BackupVconfig(local) BackupMconfig(local) CreateSymlinks(local) + EnableMode(local) #end define diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 941e16cc..6a4fbbb1 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -888,3 +888,9 @@ def CreateSymlinks(local): file.write(fiftpath + '\n') file.close() #end define + + +def EnableMode(local): + if local.buffer.mode == 'liteserver': + args = ["python3", "-m", "mytoncore", "-e", "enable_liteserver_mode"] + subprocess.run(args) diff --git a/scripts/install.sh b/scripts/install.sh index b57b9453..cfe84c76 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -15,16 +15,18 @@ fi author="ton-blockchain" repo="mytonctrl" branch="master" +mode="validator" show_help_and_exit() { - echo 'Supported argumets:' - echo ' -c PATH Provide custom config for toninstaller.sh' - echo ' -t Disable telemetry' - echo ' -i Ignore minimum reqiurements' - echo ' -d Use pre-packaged dump. Reduces duration of initial synchronization.' - echo ' -a Set MyTonCtrl git repo author' + echo 'Supported argumets:' + echo ' -c PATH Provide custom config for toninstaller.sh' + echo ' -t Disable telemetry' + echo ' -i Ignore minimum reqiurements' + echo ' -d Use pre-packaged dump. Reduces duration of initial synchronization.' + echo ' -a Set MyTonCtrl git repo author' echo ' -r Set MyTonCtrl git repo' echo ' -b Set MyTonCtrl git repo branch' + echo ' -m MODE Install MyTonCtrl with specified mode (validator or liteserver)' echo ' -h Show this help' exit } @@ -40,7 +42,8 @@ ignore=false dump=false -while getopts c:tida:r:b: flag + +while getopts c:tida:r:b:m: flag do case "${flag}" in c) config=${OPTARG};; @@ -50,6 +53,7 @@ do a) author=${OPTARG};; r) repo=${OPTARG};; b) branch=${OPTARG};; + m) mode=${OPTARG};; h) show_help_and_exit;; *) echo "Flag -${flag} is not recognized. Aborting" @@ -115,7 +119,7 @@ if [ "$parent_name" = "sudo" ] || [ "$parent_name" = "su" ]; then user=$(logname) fi echo "User: $user" -python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} +python3 -m mytoninstaller -u ${user} -t ${telemetry} --dump ${dump} -m ${mode} # set migrate version migrate_version=1 From 979a925f0e88ed07c8f0577be5d8afa0f28aea21 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 15 May 2024 19:07:04 +0700 Subject: [PATCH 194/236] bugfix --- modules/liteserver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/liteserver.py b/modules/liteserver.py index 63833ea8..02b3521a 100644 --- a/modules/liteserver.py +++ b/modules/liteserver.py @@ -2,7 +2,6 @@ from modules.module import MtcModule from mytoninstaller.mytoninstaller import set_node_argument -from mytoninstaller.node_args import get_node_args class LiteserverModule(MtcModule): @@ -18,6 +17,7 @@ def enable(self): set_node_argument(self.local, ["--celldb-cache-size", "1073741824"]) def disable(self): + from mytoninstaller.node_args import get_node_args set_node_argument(self.local, ["--celldb-no-preload-all", "-d"]) if get_node_args()['--celldb-cache-size']: set_node_argument(self.local, ["--celldb-cache-size", "-d"]) From 00c6c9fbb8352dc9477f8bac9ba2136a2b35f3f6 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 15 May 2024 20:09:31 +0700 Subject: [PATCH 195/236] bugfix --- modules/liteserver.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/liteserver.py b/modules/liteserver.py index 02b3521a..6e3849ec 100644 --- a/modules/liteserver.py +++ b/modules/liteserver.py @@ -1,7 +1,6 @@ import psutil from modules.module import MtcModule -from mytoninstaller.mytoninstaller import set_node_argument class LiteserverModule(MtcModule): @@ -10,6 +9,7 @@ class LiteserverModule(MtcModule): default_value = False def enable(self): + from mytoninstaller.mytoninstaller import set_node_argument set_node_argument(self.local, ["--celldb-no-preload-all"]) data = psutil.virtual_memory() ram = data.total / 2**30 @@ -17,6 +17,7 @@ def enable(self): set_node_argument(self.local, ["--celldb-cache-size", "1073741824"]) def disable(self): + from mytoninstaller.mytoninstaller import set_node_argument from mytoninstaller.node_args import get_node_args set_node_argument(self.local, ["--celldb-no-preload-all", "-d"]) if get_node_args()['--celldb-cache-size']: From 0b2839fb356df7a0def9e15e879eb22690a3b124 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Fri, 17 May 2024 11:48:32 +0300 Subject: [PATCH 196/236] install requirements before migration --- mytonctrl.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mytonctrl.py b/mytonctrl.py index 6c6eb9d5..4056f883 100644 --- a/mytonctrl.py +++ b/mytonctrl.py @@ -5,6 +5,13 @@ # import os import sys +import subprocess + +requirements_path = "/usr/src/mytonctrl/requirements.txt" +if os.path.isfile(requirements_path): + args = ["pip3", "install", "-r", requirements_path] + subprocess.run(args) +#end if sys.path.insert(0, '/usr/bin/mytonctrl') # Add path to mytonctrl module From 302c498cc6b8ea85d22ffe8cd507ed5572661350 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 17 May 2024 18:02:57 +0700 Subject: [PATCH 197/236] sort complaints Sort complaints by their creation time so all validators can vote for same complaints as they are in determenistic order --- mytoncore/mytoncore.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index f230c381..ffa5d3ab 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -2280,6 +2280,9 @@ def GetComplaints(self, electionId=None, past=False): complaints[chash] = item #end for + # sort complaints by their creation time and hash + complaints = dict(sorted(complaints.items(), key=lambda item: (item[1]["createdTime"], item[0]))) + # Set buffer self.SetFunctionBuffer(bname, complaints) From 3614119529e31caae97e0b920c80173887a81503 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 20 May 2024 13:42:19 +0700 Subject: [PATCH 198/236] fix git config in status and telemetry --- mytoncore/functions.py | 5 ++++- mytonctrl/mytonctrl.py | 19 +++---------------- mytonctrl/utils.py | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 12e36ba3..0cca873a 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -10,6 +10,7 @@ import subprocess from mytoncore.mytoncore import MyTonCore +from mytonctrl.utils import fix_git_config from mytoninstaller.config import GetConfig from mypylib.mypylib import ( b2mb, @@ -420,7 +421,9 @@ def Telemetry(local, ton): # Get git hashes gitHashes = dict() - gitHashes["mytonctrl"] = get_git_hash("/usr/src/mytonctrl") + mtc_path = "/usr/src/mytonctrl" + local.try_function(fix_git_config, args=[mtc_path]) + gitHashes["mytonctrl"] = get_git_hash(mtc_path) gitHashes["validator"] = GetBinGitHash( "/usr/bin/ton/validator-engine/validator-engine") data["gitHashes"] = gitHashes diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 43ace71c..138aee8d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -40,7 +40,7 @@ GetBinGitHash, ) from mytonctrl.migrate import run_migrations -from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime +from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime, fix_git_config import sys, getopt, os @@ -290,21 +290,6 @@ def check_vport(local, ton): #end define -def fix_git_config(git_path: str): - args = ["git", "status"] - try: - process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=git_path, timeout=3) - err = process.stderr.decode("utf-8") - except Exception as e: - err = str(e) - if err: - if 'git config --global --add safe.directory' in err: - args = ["git", "config", "--global", "--add", "safe.directory", git_path] - subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) - else: - raise Exception(f'Failed to check git status: {err}') -#end define - def check_git(input_args, default_repo, text): src_dir = "/usr/src" git_path = f"{src_dir}/{default_repo}" @@ -708,6 +693,8 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid validatorBinGitPath = "/usr/bin/ton/validator-engine/validator-engine" mtcGitHash = get_git_hash(mtcGitPath, short=True) validatorGitHash = GetBinGitHash(validatorBinGitPath, short=True) + fix_git_config(mtcGitPath) + fix_git_config(validatorGitPath) mtcGitBranch = get_git_branch(mtcGitPath) validatorGitBranch = get_git_branch(validatorGitPath) mtcGitHash_text = bcolors.yellow_text(mtcGitHash) diff --git a/mytonctrl/utils.py b/mytonctrl/utils.py index 12dba3c9..ba6cd105 100644 --- a/mytonctrl/utils.py +++ b/mytonctrl/utils.py @@ -1,3 +1,4 @@ +import subprocess import time @@ -12,3 +13,19 @@ def GetItemFromList(data, index): return data[index] except: pass + + +def fix_git_config(git_path: str): + args = ["git", "status"] + try: + process = subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=git_path, timeout=3) + err = process.stderr.decode("utf-8") + except Exception as e: + err = str(e) + if err: + if 'git config --global --add safe.directory' in err: + args = ["git", "config", "--global", "--add", "safe.directory", git_path] + subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3) + else: + raise Exception(f'Failed to check git status: {err}') +#end define From de3d7579080daca23bbeae99bb11c68b2690442b Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 20 May 2024 20:30:44 +0700 Subject: [PATCH 199/236] move deposit/withdraw from pools to PoolModule --- modules/nominator_pool.py | 40 --------------------------------------- modules/pool.py | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index ad72a94c..c4f263d2 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -78,42 +78,6 @@ def activate_pool(self, args): self.do_activate_pool(pool) color_print("ActivatePool - {green}OK{endc}") - def do_deposit_to_pool(self, pool_addr, amount): - wallet = self.ton.GetValidatorWallet() - bocPath = self.ton.local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" - fiftScript = self.ton.contractsDir + "nominator-pool/func/validator-deposit.fif" - args = [fiftScript, bocPath] - result = self.ton.fift.Run(args) - resultFilePath = self.ton.SignBocWithWallet(wallet, bocPath, pool_addr, amount) - self.ton.SendFile(resultFilePath, wallet) - - def deposit_to_pool(self, args): - try: - poll_addr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") - return - self.do_deposit_to_pool(poll_addr, amount) - color_print("DepositToPool - {green}OK{endc}") - - def do_withdraw_from_pool(self, pool_addr, amount): - pool_data = self.ton.GetPoolData(pool_addr) - if pool_data["state"] == 0: - self.ton.WithdrawFromPoolProcess(pool_addr, amount) - else: - self.ton.PendWithdrawFromPool(pool_addr, amount) - - def withdraw_from_pool(self, args): - try: - pool_addr = args[0] - amount = float(args[1]) - except: - color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") - return - self.do_withdraw_from_pool(pool_addr, amount) - color_print("WithdrawFromPool - {green}OK{endc}") - def update_validator_set(self, args): try: pool_addr = args[0] @@ -127,8 +91,4 @@ def update_validator_set(self, args): def add_console_commands(self, console): console.AddItem("new_pool", self.new_pool, self.local.translate("new_pool_cmd")) console.AddItem("activate_pool", self.activate_pool, self.local.translate("activate_pool_cmd")) - console.AddItem("deposit_to_pool", self.deposit_to_pool, self.local.translate("deposit_to_pool_cmd")) - console.AddItem("withdraw_from_pool", self.withdraw_from_pool, self.local.translate("withdraw_from_pool_cmd")) console.AddItem("update_validator_set", self.update_validator_set, self.local.translate("update_validator_set_cmd")) - - diff --git a/modules/pool.py b/modules/pool.py index 16b481c5..ba37b16c 100644 --- a/modules/pool.py +++ b/modules/pool.py @@ -58,7 +58,45 @@ def check_download_pool_contract_scripts(self): if not os.path.isdir(contract_path): self.ton.DownloadContract("https://github.com/ton-blockchain/nominator-pool") + def do_deposit_to_pool(self, pool_addr, amount): + wallet = self.ton.GetValidatorWallet() + bocPath = self.ton.local.buffer.my_temp_dir + wallet.name + "validator-deposit-query.boc" + fiftScript = self.ton.contractsDir + "nominator-pool/func/validator-deposit.fif" + args = [fiftScript, bocPath] + result = self.ton.fift.Run(args) + resultFilePath = self.ton.SignBocWithWallet(wallet, bocPath, pool_addr, amount) + self.ton.SendFile(resultFilePath, wallet) + + def deposit_to_pool(self, args): + try: + poll_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} deposit_to_pool ") + return + self.do_deposit_to_pool(poll_addr, amount) + color_print("DepositToPool - {green}OK{endc}") + + def do_withdraw_from_pool(self, pool_addr, amount): + pool_data = self.ton.GetPoolData(pool_addr) + if pool_data["state"] == 0: + self.ton.WithdrawFromPoolProcess(pool_addr, amount) + else: + self.ton.PendWithdrawFromPool(pool_addr, amount) + + def withdraw_from_pool(self, args): + try: + pool_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_pool ") + return + self.do_withdraw_from_pool(pool_addr, amount) + color_print("WithdrawFromPool - {green}OK{endc}") + def add_console_commands(self, console): console.AddItem("pools_list", self.print_pools_list, self.local.translate("pools_list_cmd")) console.AddItem("delete_pool", self.delete_pool, self.local.translate("delete_pool_cmd")) console.AddItem("import_pool", self.import_pool, self.local.translate("import_pool_cmd")) + console.AddItem("deposit_to_pool", self.deposit_to_pool, self.local.translate("deposit_to_pool_cmd")) + console.AddItem("withdraw_from_pool", self.withdraw_from_pool, self.local.translate("withdraw_from_pool_cmd")) From bea19f9b177a971437a2d99384cf078795925410 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 21 May 2024 15:53:16 +0700 Subject: [PATCH 200/236] remove en(dis)abling ls mode --- modules/liteserver.py | 15 --------------- mytoncore/mytoncore.py | 3 --- 2 files changed, 18 deletions(-) diff --git a/modules/liteserver.py b/modules/liteserver.py index 6e3849ec..536c9859 100644 --- a/modules/liteserver.py +++ b/modules/liteserver.py @@ -8,20 +8,5 @@ class LiteserverModule(MtcModule): description = 'For liteserver usage only - can\'t be used with validator.' default_value = False - def enable(self): - from mytoninstaller.mytoninstaller import set_node_argument - set_node_argument(self.local, ["--celldb-no-preload-all"]) - data = psutil.virtual_memory() - ram = data.total / 2**30 - if ram < 100: - set_node_argument(self.local, ["--celldb-cache-size", "1073741824"]) - - def disable(self): - from mytoninstaller.mytoninstaller import set_node_argument - from mytoninstaller.node_args import get_node_args - set_node_argument(self.local, ["--celldb-no-preload-all", "-d"]) - if get_node_args()['--celldb-cache-size']: - set_node_argument(self.local, ["--celldb-cache-size", "-d"]) - def add_console_commands(self, console): ... diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index ffa5d3ab..f72f26ba 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3269,7 +3269,6 @@ def check_enable_mode(self, name): if self.using_validator(): raise Exception(f'Cannot enable liteserver mode while validator mode is enabled. ' f'Use `disable_mode validator` first.') - MODES['liteserver'](self, self.local).enable() if name == 'validator': if self.using_liteserver(): raise Exception(f'Cannot enable validator mode while liteserver mode is enabled. ' @@ -3287,8 +3286,6 @@ def disable_mode(self, name): current_modes = self.get_modes() if name not in current_modes: raise Exception(f'Unknown module name: {name}. Available modes: {", ".join(MODES)}') - if name == 'liteserver': - MODES['liteserver'](self, self.local).disable() current_modes[name] = False self.local.save() From 3c53e6e16564ea2dab04d269770c69f5277b9eee Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 21 May 2024 16:02:09 +0700 Subject: [PATCH 201/236] add validator installation mode --- modules/liteserver.py | 2 +- mytoncore/functions.py | 9 +++++++++ mytoninstaller/settings.py | 7 +++++-- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/liteserver.py b/modules/liteserver.py index 536c9859..35acb224 100644 --- a/modules/liteserver.py +++ b/modules/liteserver.py @@ -5,7 +5,7 @@ class LiteserverModule(MtcModule): - description = 'For liteserver usage only - can\'t be used with validator.' + description = 'For liteserver usage only without validator.' default_value = False def add_console_commands(self, console): diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 0cca873a..97b0f8d3 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -57,6 +57,8 @@ def Event(local, event_name): enable_ton_storage_provider_event(local) elif event_name == "enable_liteserver_mode": enable_liteserver_mode(local) + elif event_name == "enable_validator_mode": + enable_validator_mode(local) local.exit() # end define @@ -93,10 +95,17 @@ def enable_ton_storage_provider_event(local): #end define +def enable_validator_mode(local): + from mytoninstaller.mytoninstaller import set_node_argument + set_node_argument(local, ['--archive-ttl', '86400']) # limit validator archive ttl to 1 day + + def enable_liteserver_mode(local): + from mytoninstaller.mytoninstaller import set_node_argument ton = MyTonCore(local) ton.disable_mode('validator') ton.enable_mode('liteserver') + set_node_argument(local, ['--archive-ttl', '2592000']) # limit liteserver archive ttl to 30 days #end define diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 6a4fbbb1..995dca30 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -891,6 +891,9 @@ def CreateSymlinks(local): def EnableMode(local): + args = ["python3", "-m", "mytoncore", "-e"] if local.buffer.mode == 'liteserver': - args = ["python3", "-m", "mytoncore", "-e", "enable_liteserver_mode"] - subprocess.run(args) + args.append("enable_liteserver_mode") + elif local.buffer.mode == 'validator': + args.append("enable_validator_mode") + subprocess.run(args) From 6c615633073e8f70197b82e1237c1764621ceebd Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 21 May 2024 16:22:53 +0700 Subject: [PATCH 202/236] run installer commands in mtc console --- mytonctrl/mytonctrl.py | 6 ++++-- mytoninstaller/mytoninstaller.py | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 138aee8d..272d6b65 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -249,8 +249,10 @@ def PreUp(local, ton): def Installer(args): # args = ["python3", "/usr/src/mytonctrl/mytoninstaller.py"] - args = ["python3", "-m", "mytoninstaller"] - subprocess.run(args) + cmd = ["python3", "-m", "mytoninstaller"] + if args: + cmd += ["-c", *args] + subprocess.run(cmd) #end define diff --git a/mytoninstaller/mytoninstaller.py b/mytoninstaller/mytoninstaller.py index d8c51cca..160b9210 100644 --- a/mytoninstaller/mytoninstaller.py +++ b/mytoninstaller/mytoninstaller.py @@ -238,12 +238,29 @@ def Event(local, name): #end define -def General(local): +def Command(local, args, console): + cmd = args[0] + args = args[1:] + for item in console.menu_items: + if cmd == item.cmd: + console._try(item.func, args) + print() + local.exit() + print(console.unknown_cmd) + local.exit() +#end define + + +def General(local, console): if "-u" in sys.argv: ux = sys.argv.index("-u") user = sys.argv[ux+1] local.buffer.user = user Refresh(local) + if "-c" in sys.argv: + cx = sys.argv.index("-c") + args = sys.argv[cx+1:] + Command(local, args, console) if "-e" in sys.argv: ex = sys.argv.index("-e") name = sys.argv[ex+1] @@ -282,7 +299,7 @@ def mytoninstaller(): Init(local, console) if len(sys.argv) > 1: - General(local) + General(local, console) else: console.Run() local.exit() From 3fdd42acf4925534f5f43e0ae1205c966583a133 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 21 May 2024 19:22:28 +0700 Subject: [PATCH 203/236] move setting archive ttl to FN --- mytoncore/functions.py | 9 --------- mytoninstaller/settings.py | 6 ++---- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/mytoncore/functions.py b/mytoncore/functions.py index 97b0f8d3..0cca873a 100755 --- a/mytoncore/functions.py +++ b/mytoncore/functions.py @@ -57,8 +57,6 @@ def Event(local, event_name): enable_ton_storage_provider_event(local) elif event_name == "enable_liteserver_mode": enable_liteserver_mode(local) - elif event_name == "enable_validator_mode": - enable_validator_mode(local) local.exit() # end define @@ -95,17 +93,10 @@ def enable_ton_storage_provider_event(local): #end define -def enable_validator_mode(local): - from mytoninstaller.mytoninstaller import set_node_argument - set_node_argument(local, ['--archive-ttl', '86400']) # limit validator archive ttl to 1 day - - def enable_liteserver_mode(local): - from mytoninstaller.mytoninstaller import set_node_argument ton = MyTonCore(local) ton.disable_mode('validator') ton.enable_mode('liteserver') - set_node_argument(local, ['--archive-ttl', '2592000']) # limit liteserver archive ttl to 30 days #end define diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 995dca30..993a1531 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -34,6 +34,7 @@ def FirstNodeSettings(local): validatorAppPath = local.buffer.validator_app_path globalConfigPath = local.buffer.global_config_path vconfig_path = local.buffer.vconfig_path + archive_ttl = 2592000 if local.buffer.mode == 'liteserver' else 86400 # Проверить конфигурацию if os.path.isfile(vconfig_path): @@ -57,8 +58,7 @@ def FirstNodeSettings(local): # Прописать автозагрузку cpus = psutil.cpu_count() - 1 - cmd = "{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --verbosity 1" - cmd = cmd.format(validatorAppPath=validatorAppPath, globalConfigPath=globalConfigPath, ton_db_dir=ton_db_dir, tonLogPath=tonLogPath, cpus=cpus) + cmd = f"{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --archive-ttl {archive_ttl} --verbosity 1" add2systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" # Получить внешний ip адрес @@ -894,6 +894,4 @@ def EnableMode(local): args = ["python3", "-m", "mytoncore", "-e"] if local.buffer.mode == 'liteserver': args.append("enable_liteserver_mode") - elif local.buffer.mode == 'validator': - args.append("enable_validator_mode") subprocess.run(args) From 03dd9c6b4f4eb0bdd3f88030618301b4d97e5a98 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 22 May 2024 12:24:03 +0700 Subject: [PATCH 204/236] fix installing ls mode --- mytoninstaller/settings.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 993a1531..9f4ca19f 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -894,4 +894,7 @@ def EnableMode(local): args = ["python3", "-m", "mytoncore", "-e"] if local.buffer.mode == 'liteserver': args.append("enable_liteserver_mode") + else: + return + args = ["su", "-l", local.buffer.user, "-c", ' '.join(args)] subprocess.run(args) From 2c67a1c2ed0c22cbf4ef7aefcb00fc9a4e97bb97 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 22 May 2024 13:07:05 +0700 Subject: [PATCH 205/236] add more warnings --- mytonctrl/mytonctrl.py | 26 +++++++++++++++++++++++++- mytonctrl/resources/translate.json | 20 ++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 138aee8d..3bb86107 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -39,6 +39,7 @@ GetSwapInfo, GetBinGitHash, ) +from mytoncore.telemetry import is_host_virtual from mytonctrl.migrate import run_migrations from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime, fix_git_config @@ -237,7 +238,7 @@ def check_installer_user(local): #end define -def PreUp(local, ton): +def PreUp(local: MyPyClass, ton: MyTonCore): CheckMytonctrlUpdate(local) check_installer_user(local) check_vport(local, ton) @@ -452,8 +453,31 @@ def check_disk_usage(local, ton): print_warning(local, "disk_usage_warning") #end define +def check_sync(local, ton): + validator_status = ton.GetValidatorStatus() + if validator_status.out_of_sync >= 20: + print_warning(local, "sync_warning") +#end define + +def check_validator_balance(local, ton): + if ton.using_validator(): + validator_wallet = ton.GetValidatorWallet() + validator_account = ton.GetAccount(validator_wallet.addrB64) + if validator_account.balance < 100: + print_warning(local, "validator_balance_warning") +#end define + +def check_vps(local, ton): + if ton.using_validator(): + data = local.try_function(is_host_virtual) + if data and data["virtual"]: + color_print(f"Virtualization detected: {data['product_name']}") + def warnings(local, ton): check_disk_usage(local, ton) + check_sync(local, ton) + check_validator_balance(local, ton) + check_vps(local, ton) #end define def CheckTonUpdate(local): diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index a4a59c47..6b3a2823 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -419,6 +419,26 @@ "ru": "{green}Доступно обновление TON. {red}Пожалуйста, обновите его с помощью команды `upgrade`.{endc}", "zh_TW": "{green}TON 有可用更新. {red}請使用 `upgrade` 命令進行更新.{endc}" }, + "disk_usage_warning": { + "en": "{red} Disk is almost full, clean the TON database immediately: https://docs.ton.org/participate/nodes/node-maintenance-and-security#database-grooming {endc}", + "ru": "{red} Диск почти заполнен, немедленно очистите базу данных TON: https://docs.ton.org/participate/nodes/node-maintenance-and-security#database-grooming {endc}", + "zh_TW": "{red} 磁盤幾乎滿了,立即清理 TON 數據庫: https://docs.ton.org/participate/nodes/node-maintenance-and-security#database-grooming {endc}" + }, + "sync_warning": { + "en": "{red} Node is out of sync. The displayed status is incomplete. {endc}", + "ru": "{red} Нода не синхронизирована с сетью. Отображаемый статус не полный. {endc}", + "zh_TW": "{red} 节点不与网络同步。顯示的狀態不完整。 {endc}" + }, + "validator_balance_warning": { + "en": "{red} Validator wallet balance is low. {endc}", + "ru": "{red} Баланс кошелька валидатора низкий. {endc}", + "zh_TW": "{red} 驗證者錢包餘額不足。 {endc}" + }, + "vps_warning": { + "en": "{red} Validator is running on a VPS. Use a dedicated server for better performance. {endc}", + "ru": "{red} Валидатор работает на VPS. Используйте выделенный сервер (дедик) для лучшей производительности. {endc}", + "zh_TW": "{red} 驗證者在 VPS 上運行。使用專用服務器以獲得更好的性能。 {endc}" + }, "vport_error": { "en": "{red}Error - UDP port of the validator is not accessible from the outside.{endc}", "ru": "{red}Ошибка - UDP порт валидатора недоступен извне.{endc}", From 251b127d4d96e4bcec75c52722c9f7cd7831ea58 Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 22 May 2024 13:09:21 +0700 Subject: [PATCH 206/236] bugfix --- mytonctrl/mytonctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 3bb86107..8cc5089f 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -455,7 +455,7 @@ def check_disk_usage(local, ton): def check_sync(local, ton): validator_status = ton.GetValidatorStatus() - if validator_status.out_of_sync >= 20: + if not validator_status.is_working or validator_status.out_of_sync >= 20: print_warning(local, "sync_warning") #end define From 2f18f031344ba6affe74a24c40041f4d359de18e Mon Sep 17 00:00:00 2001 From: yungwine Date: Wed, 22 May 2024 13:19:11 +0700 Subject: [PATCH 207/236] bugfix --- mytonctrl/mytonctrl.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index cc7c84c5..28d2b16c 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -464,7 +464,10 @@ def check_sync(local, ton): def check_validator_balance(local, ton): if ton.using_validator(): validator_wallet = ton.GetValidatorWallet() - validator_account = ton.GetAccount(validator_wallet.addrB64) + validator_account = local.try_function(ton.GetAccount, args=[validator_wallet.addrB64]) + if validator_account is None: + local.add_log(f"Failed to check validator wallet balance", "warning") + return if validator_account.balance < 100: print_warning(local, "validator_balance_warning") #end define From 722411b7914e94e913cb481b597bfd66031e016e Mon Sep 17 00:00:00 2001 From: yungwine Date: Sat, 25 May 2024 20:45:41 +0700 Subject: [PATCH 208/236] add default branch param to check_git --- mytonctrl/mytonctrl.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 28d2b16c..f14f1c0a 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -293,13 +293,11 @@ def check_vport(local, ton): #end define -def check_git(input_args, default_repo, text): +def check_git(input_args, default_repo, text, default_branch='master'): src_dir = "/usr/src" git_path = f"{src_dir}/{default_repo}" fix_git_config(git_path) default_author = "ton-blockchain" - # default_branch = "master" - default_branch = "mytonctrl2" # Get author, repo, branch local_author, local_repo = get_git_author_and_repo(git_path) @@ -341,7 +339,7 @@ def check_branch_exists(author, repo, branch): def Update(local, args): repo = "mytonctrl" - author, repo, branch = check_git(args, repo, "update") + author, repo, branch = check_git(args, repo, "update", default_branch='mytonctrl2') # Run script update_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/update.sh') From 390ea684020b1e6e0f2c75dbecdd644829e6b683 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 26 May 2024 20:17:26 +0300 Subject: [PATCH 209/236] WalletVersion2Wallet bugfix --- mytoncore/mytoncore.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index f72f26ba..3693e682 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -497,20 +497,18 @@ def AddrFile2Object(self, object): #end define def WalletVersion2Wallet(self, wallet): - self.local.add_log("start WalletVersion2Wallet function", "debug") if wallet.version is not None: return + self.local.add_log("start WalletVersion2Wallet function", "debug") walletsVersionList = self.GetWalletsVersionList() - account = self.GetAccount(wallet.addrB64) version = walletsVersionList.get(wallet.addrB64) if version is None: + account = self.GetAccount(wallet.addrB64) version = self.GetVersionFromCodeHash(account.codeHash) + self.SetWalletVersion(wallet.addrB64, version) if version is None: self.local.add_log("Wallet version not found: " + wallet.addrB64, "warning") return - #end if - - self.SetWalletVersion(wallet.addrB64, version) wallet.version = version #end define From 32e8628d134465a1461bbb8675b881ace2372916 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 26 May 2024 23:02:41 +0300 Subject: [PATCH 210/236] do_activate_pool bugfix --- modules/nominator_pool.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index c4f263d2..caa18c23 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -56,14 +56,14 @@ def new_pool(self, args): def do_activate_pool(self, pool, ex=True): self.ton.local.add_log("start ActivatePool function", "debug") - for i in range(10): - time.sleep(3) - account = self.ton.GetAccount(pool.addrB64) - if account.balance > 0: - self.ton.SendFile(pool.bocFilePath, pool, timeout=False) - return - if ex: - raise Exception("ActivatePool error: time out") + account = self.ton.GetAccount(pool.addrB64) + if account.status == "empty": + raise Exception("do_activate_pool error: account status is empty") + elif account.status == "active": + self.local.add_log("do_activate_pool warning: account status is active", "warning") + else: + self.SendFile(pool.bocFilePath, pool, timeout=False, remove=False) + #end define def activate_pool(self, args): try: @@ -72,9 +72,6 @@ def activate_pool(self, args): color_print("{red}Bad args. Usage:{endc} activate_pool ") return pool = self.ton.GetLocalPool(pool_name) - if not os.path.isfile(pool.bocFilePath): - self.local.add_log(f"Pool {pool_name} already activated", "warning") - return self.do_activate_pool(pool) color_print("ActivatePool - {green}OK{endc}") From ee55002be4cc122c68bf6f8a89a84dda8ab47c82 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 26 May 2024 23:07:56 +0300 Subject: [PATCH 211/236] add withdraw_from_single_pool --- modules/single_pool.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/modules/single_pool.py b/modules/single_pool.py index 748cc4fd..d2721c5a 100644 --- a/modules/single_pool.py +++ b/modules/single_pool.py @@ -67,6 +67,18 @@ def activate_single_pool(self, args): self.do_activate_single_pool(pool) color_print("activate_single_pool - {green}OK{endc}") + def withdraw_from_single_pool(self, args): + try: + pool_addr = args[0] + amount = float(args[1]) + except: + color_print("{red}Bad args. Usage:{endc} withdraw_from_single_pool ") + return + self.ton.WithdrawFromPoolProcess(pool_addr, amount) + color_print("withdraw_from_single_pool - {green}OK{endc}") + #end define + def add_console_commands(self, console): console.AddItem("new_single_pool", self.new_single_pool, self.local.translate("new_single_pool_cmd")) console.AddItem("activate_single_pool", self.activate_single_pool, self.local.translate("activate_single_pool_cmd")) + console.AddItem("withdraw_from_single_pool", self.withdraw_from_single_pool, self.local.translate("withdraw_from_single_pool_cmd")) From fa09221ba5a2bf3872c71dbc34277fa59e8e4030 Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Sun, 26 May 2024 23:25:34 +0300 Subject: [PATCH 212/236] update check_validator_balance Do not check the validator wallet balance if the node is not synchronized (via public lite-servers) --- mytonctrl/mytonctrl.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 28d2b16c..99ed9b56 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -462,6 +462,10 @@ def check_sync(local, ton): #end define def check_validator_balance(local, ton): + validator_status = ton.GetValidatorStatus() + if not validator_status.is_working or validator_status.out_of_sync >= 20: + # Do not check the validator wallet balance if the node is not synchronized (via public lite-servers) + return if ton.using_validator(): validator_wallet = ton.GetValidatorWallet() validator_account = local.try_function(ton.GetAccount, args=[validator_wallet.addrB64]) @@ -477,6 +481,7 @@ def check_vps(local, ton): data = local.try_function(is_host_virtual) if data and data["virtual"]: color_print(f"Virtualization detected: {data['product_name']}") +#end define def warnings(local, ton): check_disk_usage(local, ton) From 0f3197a1c9226091dd81c2f8401c331225f623bc Mon Sep 17 00:00:00 2001 From: Igroman787 <27614297+igroman787@users.noreply.github.com> Date: Mon, 27 May 2024 15:54:28 +0300 Subject: [PATCH 213/236] update mypylib --- mypylib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mypylib b/mypylib index 1d8fd217..049205ee 160000 --- a/mypylib +++ b/mypylib @@ -1 +1 @@ -Subproject commit 1d8fd2172639b7c6d61ded311d2c3a47d60c16b0 +Subproject commit 049205eee1650d7d847497d78acba68c5a33cc37 From 9788e72dcf518bb78209e371914f67c48fee31a8 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 28 May 2024 14:22:10 +0700 Subject: [PATCH 214/236] fix GetSaveOffers for old version --- mytoncore/mytoncore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index f72f26ba..5f0663b3 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3047,7 +3047,7 @@ def offers_gc(self, save_offers): def GetSaveOffers(self): bname = "saveOffers" save_offers = self.local.db.get(bname) - if save_offers is None: + if save_offers is None or isinstance(save_offers, list): save_offers = dict() self.local.db[bname] = save_offers self.offers_gc(save_offers) From 626d4f464bea90cee7770b6d0c8bafef84eb4f1a Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 28 May 2024 14:44:03 +0700 Subject: [PATCH 215/236] support custom block overlays --- modules/custom_overlays.py | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/modules/custom_overlays.py b/modules/custom_overlays.py index e951318c..4ca7331e 100644 --- a/modules/custom_overlays.py +++ b/modules/custom_overlays.py @@ -31,12 +31,20 @@ def parse_config(name: str, config: dict, vset: list = None): "msg_sender": False, }) else: - result["nodes"].append({ - "adnl_id": hex2base64(k), - "msg_sender": v["msg_sender"], - }) - if v["msg_sender"]: - result["nodes"][-1]["msg_sender_priority"] = v["msg_sender_priority"] + if "block_sender" in v: + result["nodes"].append({ + "adnl_id": hex2base64(k), + "block_sender": v["block_sender"], + }) + elif "msg_sender" in v: + result["nodes"].append({ + "adnl_id": hex2base64(k), + "msg_sender": v["msg_sender"], + }) + if v["msg_sender"]: + result["nodes"][-1]["msg_sender_priority"] = v["msg_sender_priority"] + else: + raise Exception("Unknown node type") return result def add_custom_overlay(self, args): From 1fce2cda03ca6e4a0284d2deae0e7e193cd79584 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 28 May 2024 14:51:39 +0700 Subject: [PATCH 216/236] add timeout --- modules/custom_overlays.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/custom_overlays.py b/modules/custom_overlays.py index 4ca7331e..efa82dd8 100644 --- a/modules/custom_overlays.py +++ b/modules/custom_overlays.py @@ -176,7 +176,7 @@ def get_default_custom_overlay(self): network = self.ton.GetNetworkName() default_url = 'https://ton-blockchain.github.io/fallback_custom_overlays.json' url = self.ton.local.db.get('defaultCustomOverlaysUrl', default_url) - resp = requests.get(url) + resp = requests.get(url, timeout=3) if resp.status_code != 200: self.ton.local.add_log(f"Failed to get default custom overlays from {url}", "error") return None From 08ef16253e05eed63a2974a4a5ab59a4bfdd8977 Mon Sep 17 00:00:00 2001 From: Maksim Kurbatov <94808996+yungwine@users.noreply.github.com> Date: Tue, 28 May 2024 17:41:32 +0700 Subject: [PATCH 217/236] fix do_activate_pool --- modules/nominator_pool.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index caa18c23..a5adcc4b 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -62,7 +62,7 @@ def do_activate_pool(self, pool, ex=True): elif account.status == "active": self.local.add_log("do_activate_pool warning: account status is active", "warning") else: - self.SendFile(pool.bocFilePath, pool, timeout=False, remove=False) + self.ton.SendFile(pool.bocFilePath, pool, timeout=False, remove=False) #end define def activate_pool(self, args): From c68b20d5b9c2a1bcfa6eee50d1d7581747ad0ab3 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 31 May 2024 12:30:56 +0700 Subject: [PATCH 218/236] fix printing controllers_list --- modules/controller.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/controller.py b/modules/controller.py index b9fa78ca..0acc8b1e 100644 --- a/modules/controller.py +++ b/modules/controller.py @@ -48,8 +48,9 @@ def print_controllers_list(self, args): old_controllers = self.ton.GetSettings("old_controllers") user_controllers_list = self.ton.GetSettings("user_controllers_list") print("using controllers:") - self.print_controllers_list_process(using_controllers) - if new_controllers != using_controllers: + if using_controllers is not None: + self.print_controllers_list_process(using_controllers) + if new_controllers is not None and new_controllers != using_controllers: print() print("new controllers:") self.print_controllers_list_process(new_controllers) From ab92202b34d8a0d37811666a7ccfd2c8ef426320 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 31 May 2024 12:30:56 +0700 Subject: [PATCH 219/236] add debug setting --- modules/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/__init__.py b/modules/__init__.py index 5a44fa3e..298302b0 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -52,6 +52,7 @@ class Setting: 'fift_timeout': Setting(None, 3, 'Fift default timeout'), 'useDefaultCustomOverlays': Setting(None, True, 'Participate in default custom overlays node eligible to'), 'defaultCustomOverlaysUrl': Setting(None, 'https://ton-blockchain.github.io/fallback_custom_overlays.json', 'Default custom overlays config url'), + 'debug': Setting(None, False, 'Debug mtc console mode. Prints Traceback on errors'), } From e254894b7b3ca75e110f2c5327580d6348627e63 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 31 May 2024 13:50:39 +0700 Subject: [PATCH 220/236] update state out of ser text --- mytonctrl/mytonctrl.py | 15 ++++++++++++--- mytonctrl/resources/translate.json | 6 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 99ed9b56..caaba0c4 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -551,6 +551,8 @@ def PrintStatus(local, ton, args): disks_load_percent_avg = ton.GetStatistics("disksLoadPercentAvg", statistics) all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 + config15 = None + if all_status: network_name = ton.GetNetworkName() rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() @@ -588,7 +590,7 @@ def PrintStatus(local, ton, args): if all_status: PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) PrintLocalStatus(local, adnl_addr, validator_index, validator_efficiency, validator_wallet, validator_account, validator_status, - db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg) + db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg, config15) if all_status: PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) @@ -638,7 +640,7 @@ def PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineVa print() #end define -def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg): +def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg, config15): if validatorWallet is None: return walletAddr = validatorWallet.addrB64 @@ -716,7 +718,14 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid mytoncoreStatus_text = local.translate("local_status_mytoncore_status").format(mytoncoreStatus_color, mytoncoreUptime_text) validatorStatus_text = local.translate("local_status_validator_status").format(validatorStatus_color, validatorUptime_text) validator_out_of_sync_text = local.translate("local_status_validator_out_of_sync").format(GetColorInt(validator_status.out_of_sync, 20, logic="less", ending=" s")) - validator_out_of_ser_text = local.translate("local_status_validator_out_of_ser").format(GetColorInt(validator_status.out_of_ser, 20, logic="less", ending=" blocks")) + + validator_out_of_ser_text = local.translate("local_status_validator_out_of_ser").format(f'{validator_status.out_of_ser} blocks ago') + + if config15: + t = config15["validatorsElectedFor"] * 2 + if validator_status.out_of_ser * 5 > t: + validator_out_of_ser_text = local.translate("local_status_validator_out_of_ser").format(f'{{redc}}{validator_status.out_of_ser} blocks ago{{endc}}') + dbSize_text = GetColorInt(dbSize, 1000, logic="less", ending=" Gb") dbUsage_text = GetColorInt(dbUsage, 80, logic="less", ending="%") dbStatus_text = local.translate("local_status_db").format(dbSize_text, dbUsage_text) diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 6b3a2823..90ae672e 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -330,9 +330,9 @@ "zh_TW": "本地驗證者不同步: {0}" }, "local_status_validator_out_of_ser": { - "en": "Local validator out of ser: {0}", - "ru": "Рассериализация локального валидатора: {0}", - "zh_TW": "本地驗證者不同步: {0}" + "en": "Local validator last state serialization: {0}", + "ru": "Серализация стейта локального валидатора была: {0}", + "zh_TW": "本地驗證者最後一次狀態序列化: {0}" }, "local_status_db": { "en": "Local validator database size: {0}, {1}", From 532aaf1c426db505efbe5fae732050241295a7ce Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 31 May 2024 14:05:40 +0700 Subject: [PATCH 221/236] bugfix --- mytonctrl/mytonctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index caaba0c4..c196596a 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -724,7 +724,7 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid if config15: t = config15["validatorsElectedFor"] * 2 if validator_status.out_of_ser * 5 > t: - validator_out_of_ser_text = local.translate("local_status_validator_out_of_ser").format(f'{{redc}}{validator_status.out_of_ser} blocks ago{{endc}}') + validator_out_of_ser_text = color_text(local.translate("local_status_validator_out_of_ser").format(f'{{red}}{validator_status.out_of_ser} blocks ago{{endc}}')) dbSize_text = GetColorInt(dbSize, 1000, logic="less", ending=" Gb") dbUsage_text = GetColorInt(dbUsage, 80, logic="less", ending="%") From df4dff32014e4a32a7de15cef718aba6c064c0d1 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 31 May 2024 19:58:35 +0700 Subject: [PATCH 222/236] add fullnode adnl addr --- mytonctrl/mytonctrl.py | 13 +++++++++++-- mytonctrl/resources/translate.json | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index c196596a..0d820d00 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf_8 -*- +import base64 import subprocess import json import psutil @@ -553,6 +554,12 @@ def PrintStatus(local, ton, args): all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 config15 = None + try: + vconfig = ton.GetValidatorConfig() + fullnode_adnl = base64.b64decode(vconfig.fullnode).hex().upper() + except: + fullnode_adnl = 'n/a' + if all_status: network_name = ton.GetNetworkName() rootWorkchainEnabledTime_int = ton.GetRootWorkchainEnabledTime() @@ -590,7 +597,7 @@ def PrintStatus(local, ton, args): if all_status: PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) PrintLocalStatus(local, adnl_addr, validator_index, validator_efficiency, validator_wallet, validator_account, validator_status, - db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg, config15) + db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg, config15, fullnode_adnl) if all_status: PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) @@ -640,7 +647,7 @@ def PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineVa print() #end define -def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg, config15): +def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg, config15, fullnode_adnl): if validatorWallet is None: return walletAddr = validatorWallet.addrB64 @@ -659,6 +666,7 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid validatorEfficiency_text = GetColorInt(validatorEfficiency, 10, logic="more", ending=" %") validatorEfficiency_text = local.translate("local_status_validator_efficiency").format(validatorEfficiency_text) adnlAddr_text = local.translate("local_status_adnl_addr").format(bcolors.yellow_text(adnlAddr)) + fullnode_adnl_text = local.translate("local_status_fullnode_adnl").format(bcolors.yellow_text(fullnode_adnl)) walletAddr_text = local.translate("local_status_wallet_addr").format(bcolors.yellow_text(walletAddr)) walletBalance_text = local.translate("local_status_wallet_balance").format(bcolors.green_text(walletBalance)) @@ -751,6 +759,7 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid print(validatorIndex_text) print(validatorEfficiency_text) print(adnlAddr_text) + print(fullnode_adnl_text) print(walletAddr_text) print(walletBalance_text) print(cpuLoad_text) diff --git a/mytonctrl/resources/translate.json b/mytonctrl/resources/translate.json index 90ae672e..22c2b283 100644 --- a/mytonctrl/resources/translate.json +++ b/mytonctrl/resources/translate.json @@ -284,6 +284,11 @@ "ru": "ADNL адрес локального валидатора: {0}", "zh_TW": "本地驗證者的 ADNL 地址: {0}" }, + "local_status_fullnode_adnl": { + "en": "Public ADNL address of node: {0}", + "ru": "Публичный ADNL адрес ноды: {0}", + "zh_TW": "節點的公共 ADNL 地址: {0}" + }, "local_status_wallet_addr": { "en": "Local validator wallet address: {0}", "ru": "Адрес кошелька локального валидатора: {0}", From 6aa46b3feae357cdd215954eb915c703ae2eeee6 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 4 Jun 2024 13:24:06 +0700 Subject: [PATCH 223/236] revert red color for out-of-ser --- mytonctrl/mytonctrl.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 0d820d00..78917240 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -552,7 +552,6 @@ def PrintStatus(local, ton, args): disks_load_percent_avg = ton.GetStatistics("disksLoadPercentAvg", statistics) all_status = validator_status.is_working == True and validator_status.out_of_sync < 20 - config15 = None try: vconfig = ton.GetValidatorConfig() @@ -597,7 +596,7 @@ def PrintStatus(local, ton, args): if all_status: PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineValidators, shardsNumber, offersNumber, complaintsNumber, tpsAvg) PrintLocalStatus(local, adnl_addr, validator_index, validator_efficiency, validator_wallet, validator_account, validator_status, - db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg, config15, fullnode_adnl) + db_size, db_usage, memory_info, swap_info, net_load_avg, disks_load_avg, disks_load_percent_avg, fullnode_adnl) if all_status: PrintTonConfig(local, fullConfigAddr, fullElectorAddr, config15, config17) PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkTime, config15) @@ -647,7 +646,7 @@ def PrintTonStatus(local, network_name, startWorkTime, totalValidators, onlineVa print() #end define -def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg, config15, fullnode_adnl): +def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, validatorWallet, validatorAccount, validator_status, dbSize, dbUsage, memoryInfo, swapInfo, netLoadAvg, disksLoadAvg, disksLoadPercentAvg, fullnode_adnl): if validatorWallet is None: return walletAddr = validatorWallet.addrB64 @@ -729,11 +728,6 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid validator_out_of_ser_text = local.translate("local_status_validator_out_of_ser").format(f'{validator_status.out_of_ser} blocks ago') - if config15: - t = config15["validatorsElectedFor"] * 2 - if validator_status.out_of_ser * 5 > t: - validator_out_of_ser_text = color_text(local.translate("local_status_validator_out_of_ser").format(f'{{red}}{validator_status.out_of_ser} blocks ago{{endc}}')) - dbSize_text = GetColorInt(dbSize, 1000, logic="less", ending=" Gb") dbUsage_text = GetColorInt(dbUsage, 80, logic="less", ending="%") dbStatus_text = local.translate("local_status_db").format(dbSize_text, dbUsage_text) From dfd2d61ff6dfe41b487f704f9500f929f120dde3 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 7 Jun 2024 18:41:33 +0700 Subject: [PATCH 224/236] remove state-ttl from installation --- mytoninstaller/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytoninstaller/settings.py b/mytoninstaller/settings.py index 9f4ca19f..d04c5673 100644 --- a/mytoninstaller/settings.py +++ b/mytoninstaller/settings.py @@ -58,7 +58,7 @@ def FirstNodeSettings(local): # Прописать автозагрузку cpus = psutil.cpu_count() - 1 - cmd = f"{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --state-ttl 604800 --archive-ttl {archive_ttl} --verbosity 1" + cmd = f"{validatorAppPath} --threads {cpus} --daemonize --global-config {globalConfigPath} --db {ton_db_dir} --logname {tonLogPath} --archive-ttl {archive_ttl} --verbosity 1" add2systemd(name="validator", user=vuser, start=cmd) # post="/usr/bin/python3 /usr/src/mytonctrl/mytoncore.py -e \"validator down\"" # Получить внешний ip адрес From fd782afea8543c753c79ae3ae78075210146c6f4 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 7 Jun 2024 21:04:49 +0700 Subject: [PATCH 225/236] rm state-ttl only if validator --- mytonctrl/mytonctrl.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 78917240..87b5972d 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -382,6 +382,9 @@ def Upgrade(ton, args): 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) + if ton.using_validator(): + from mytoninstaller.mytoninstaller import set_node_argument + set_node_argument(ton.local, ["--state-ttl", "-d"]) if exitCode == 0: text = "Upgrade - {green}OK{endc}" else: From 3c20a79e9b4f2d45e317957d387e7234ff5069dc Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 7 Jun 2024 21:46:09 +0700 Subject: [PATCH 226/236] rm state-ttl only if its value default --- mytonctrl/mytonctrl.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index e0fc8df3..a82c41bb 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -381,8 +381,13 @@ def Upgrade(ton, args): runArgs = ["bash", upgrade_script_path, "-a", author, "-r", repo, "-b", branch] exitCode = run_as_root(runArgs) if ton.using_validator(): - from mytoninstaller.mytoninstaller import set_node_argument - set_node_argument(ton.local, ["--state-ttl", "-d"]) + try: + from mytoninstaller.mytoninstaller import set_node_argument, get_node_args + node_args = get_node_args() + if node_args['--state-ttl'] == 604800: + set_node_argument(ton.local, ["--state-ttl", "-d"]) + except Exception as e: + color_print(f"{{red}}Failed to set node argument: {e} {{endc}}") if exitCode == 0: text = "Upgrade - {green}OK{endc}" else: From f511780fc7a14c2237f6f753fec8159426e71b86 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 7 Jun 2024 21:51:42 +0700 Subject: [PATCH 227/236] bugfix --- mytonctrl/mytonctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index a82c41bb..9598716f 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -384,7 +384,7 @@ def Upgrade(ton, args): try: from mytoninstaller.mytoninstaller import set_node_argument, get_node_args node_args = get_node_args() - if node_args['--state-ttl'] == 604800: + if node_args['--state-ttl'] == '604800': set_node_argument(ton.local, ["--state-ttl", "-d"]) except Exception as e: color_print(f"{{red}}Failed to set node argument: {e} {{endc}}") From 622c3f69195277b91e438cd47ff575c4f582004e Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 18 Jul 2024 17:37:40 +0800 Subject: [PATCH 228/236] add collator config --- modules/collator_config.py | 92 ++++++++++++++++++++++++++++++++++++++ mytoncore/mytoncore.py | 10 +++++ mytonctrl/mytonctrl.py | 4 ++ 3 files changed, 106 insertions(+) create mode 100644 modules/collator_config.py diff --git a/modules/collator_config.py b/modules/collator_config.py new file mode 100644 index 00000000..9596520c --- /dev/null +++ b/modules/collator_config.py @@ -0,0 +1,92 @@ +import json +import requests + +from mypylib.mypylib import color_print +from modules.module import MtcModule +from mytoncore.utils import hex2base64 + + +class CollatorConfigModule(MtcModule): + + @staticmethod + def check_config_url(url): + try: + r = requests.get(url, timeout=3) + if r.status_code != 200: + print(f'Failed to get config from {url}: {r.status_code} code; {r.text}') + return + return r.json() + except Exception as e: + print(f'Failed to get config from {url}: {e}') + return + + @staticmethod + def check_config_file(path): + try: + with open(path, 'r') as f: + return json.load(f) + except Exception as e: + print(f'Failed to read config from {path}: {e}') + return + + @staticmethod + def get_config(path): + if 'http' in path: + config = CollatorConfigModule.check_config_url(path) + else: + config = CollatorConfigModule.check_config_file(path) + if config is None: + raise Exception(f'Failed to get config') + return config + + def add_collator_config_to_vc(self, config: dict): + self.local.add_log(f"Adding collator options config to validator console", "debug") + path = self.ton.tempDir + f'/collator_config.json' + with open(path, 'w') as f: + json.dump(config, f) + result = self.ton.validatorConsole.Run(f"setcollatoroptionsjson {path}") + return 'success' in result, result + + def set_collator_config(self, args): + if len(args) != 1: + color_print("{red}Bad args. Usage:{endc} set_collator_config ") + return + location = args[0] + config = self.get_config(location) + self.ton.set_collator_config(location) + added, msg = self.add_collator_config_to_vc(config) + if not added: + print(f'Failed to add collator config to validator console: {msg}') + color_print("set_collator_config - {red}ERROR{endc}") + return + color_print("set_collator_config - {green}OK{endc}") + + def get_collator_config(self, args): + location = self.ton.get_collator_config_location() + print(f'Collator config location: {location}') + path = self.ton.tempDir + f'/current_collator_config.json' + output = self.ton.validatorConsole.Run(f'getcollatoroptionsjson {path}') + if 'saved config to' not in output: + print(f'Failed to get collator config: {output}') + color_print("get_collator_config - {red}ERROR{endc}") + return + with open(path, 'r') as f: + config = json.load(f) + print(f'Collator config:') + print(json.dumps(config, indent=4)) + color_print("get_collator_config - {green}OK{endc}") + + def update_collator_config(self, args): + location = self.ton.get_collator_config() + config = self.get_config(location) + added, msg = self.add_collator_config_to_vc(config) + if not added: + print(f'Failed to add collator config to validator console: {msg}') + color_print("update_collator_config - {red}ERROR{endc}") + return + color_print("update_collator_config - {green}OK{endc}") + + def add_console_commands(self, console): + console.AddItem("set_collator_config", self.set_collator_config, self.local.translate("set_collator_config_cmd")) + console.AddItem("update_collator_config", self.update_collator_config, self.local.translate("update_collator_config_cmd")) + console.AddItem("get_collator_config", self.get_collator_config, self.local.translate("get_collator_config_cmd")) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 726b0d2f..098d6ec9 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -3986,6 +3986,16 @@ def delete_custom_overlay(self, name: str): del self.local.db['custom_overlays'][name] self.local.save() + def set_collator_config(self, location: str): + self.local.db['collator_config'] = location + self.local.save() + + def get_collator_config_location(self): + default = 'https://raw.githubusercontent.com/ton-blockchain/ton-blockchain.github.io/main/default_collator_options.json' + location = self.local.db.get('collator_config', default) + if location is None: + location = default + return location def GetNetworkName(self): data = self.local.read_db(self.liteClient.configPath) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 9598716f..47e06721 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -128,6 +128,10 @@ def inject_globals(func): module = CustomOverlayModule(ton, local) module.add_console_commands(console) + from modules.collator_config import CollatorConfigModule + module = CollatorConfigModule(ton, local) + module.add_console_commands(console) + if ton.using_validator(): from modules.validator import ValidatorModule module = ValidatorModule(ton, local) From ca211e9aa747a90e8b90a26b085857501cb62509 Mon Sep 17 00:00:00 2001 From: yungwine Date: Thu, 18 Jul 2024 21:41:39 +0800 Subject: [PATCH 229/236] bugfix --- modules/collator_config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/collator_config.py b/modules/collator_config.py index 9596520c..9234b08f 100644 --- a/modules/collator_config.py +++ b/modules/collator_config.py @@ -3,7 +3,6 @@ from mypylib.mypylib import color_print from modules.module import MtcModule -from mytoncore.utils import hex2base64 class CollatorConfigModule(MtcModule): @@ -77,7 +76,7 @@ def get_collator_config(self, args): color_print("get_collator_config - {green}OK{endc}") def update_collator_config(self, args): - location = self.ton.get_collator_config() + location = self.ton.get_collator_config_location() config = self.get_config(location) added, msg = self.add_collator_config_to_vc(config) if not added: From 8849a95e513775d82a274e2b1633b5bd40aa6443 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 19 Jul 2024 14:49:47 +0800 Subject: [PATCH 230/236] remove docs, update README --- README.RU.md | 119 ------------------------------ README.md | 23 +++--- docs/en/FAQ.md | 124 -------------------------------- docs/en/controllers.md | 93 ------------------------ docs/en/import-wallets.md | 33 --------- docs/en/manual-ubuntu.md | 67 ----------------- docs/en/nominator-pool.md | 118 ------------------------------ docs/ru/FAQ.md | 122 ------------------------------- docs/ru/controllers.md | 92 ------------------------ docs/ru/import-wallets.md | 36 ---------- docs/ru/manual-ubuntu.md | 67 ----------------- docs/ru/nominator-pool.md | 118 ------------------------------ docs/ru/ton-storage-provider.md | 32 --------- docs/zh_TW/FAQ.md | 121 ------------------------------- docs/zh_TW/import-wallets.md | 36 ---------- docs/zh_TW/manual-ubuntu.md | 67 ----------------- docs/zh_TW/nominator-pool.md | 117 ------------------------------ 17 files changed, 8 insertions(+), 1377 deletions(-) delete mode 100644 README.RU.md delete mode 100644 docs/en/FAQ.md delete mode 100644 docs/en/controllers.md delete mode 100644 docs/en/import-wallets.md delete mode 100644 docs/en/manual-ubuntu.md delete mode 100644 docs/en/nominator-pool.md delete mode 100644 docs/ru/FAQ.md delete mode 100644 docs/ru/controllers.md delete mode 100644 docs/ru/import-wallets.md delete mode 100644 docs/ru/manual-ubuntu.md delete mode 100644 docs/ru/nominator-pool.md delete mode 100644 docs/ru/ton-storage-provider.md delete mode 100644 docs/zh_TW/FAQ.md delete mode 100644 docs/zh_TW/import-wallets.md delete mode 100644 docs/zh_TW/manual-ubuntu.md delete mode 100644 docs/zh_TW/nominator-pool.md diff --git a/README.RU.md b/README.RU.md deleted file mode 100644 index 91acd3d9..00000000 --- a/README.RU.md +++ /dev/null @@ -1,119 +0,0 @@ -## Что это -Данная консольная программа является оберткой над `fift`, `lite-client` и `validator-engine-console`. Она была создана для облегчения управления кошельками, доменами и валидатором на операционной системе `Linux`. -![](screens/mytonctrl-status_ru.png) - -## Функционал -- [x] Показать статус сети TON -- [x] Управление локальными кошельками - - [x] Создать локальный кошелек - - [x] Активировать локальный кошелек - - [x] Показать локальные кошельки - - [x] Импортировать кошелек из файла (.pk) - - [x] Сохранить адрес кошелька в файл (.addr) - - [x] Удалить локальный кошелек -- [x] Показать статус аккаунта - - [x] Показать баланс аккаунта - - [x] Показать историю аккаунта - - [x] Показать статус аккаунта из закладок -- [x] Перевод средств на кошелек - - [x] Перевод фиксированной суммы - - [x] Перевод всей суммы (all) - - [x] Перевод всей суммы с диактивацией кошелька (alld) - - [x] Перевод средств на кошелек из закладок - - [x] Перевод средств на кошелек через цепочку самоудаляемых кошельков -- [x] Управление закладками - - [x] Добавить аккаунт в закладки - - [x] Показать закладки - - [x] Удалить закладку -- [x] Управление предложениями - - [x] Показать предложения - - [x] Проголосовать за предложение - - [x] Автоматическое голосование за ранее проголосованные предложения -- [x] Управление доменами - - [x] Арендовать новый домен - - [x] Показать арендованные домены - - [x] Показать статус домена - - [x] Удалить домен - - [ ] Автоматическое продление доменов -- [x] Управление валидатором - - [x] Участвовать в выборах валидатора - - [x] Возвращать ставку + вознаграждение - - [x] Автозапуск валидатора при аварийном завершении (systemd) - - [x] Отправлять статистику валидатора на https://toncenter.com - -## Список проверенных операционных систем -| Operating System | Status | -|-------------------------------|----------------------------| -| Ubuntu 16.04 LTS (Xenial Xerus) | Error: TON compilation error | -| Ubuntu 18.04 LTS (Bionic Beaver) | OK | -| Ubuntu 20.04 LTS (Focal Fossa) | OK | -| Ubuntu 22.04 LTS (Jammy Jellyfish) | OK | -| Debian 8 | Error: Unable to locate package libgsl-dev | -| Debian 9 | Error: TON compilation error | -| Debian 10 | OK | - - -## Описание установочных скриптов -- `toninstaller.sh` - Данный скрипт клонирует исходники `TON` и `mytonctrl` в папки `/usr/src/ton` и `/usr/src/mytonctrl`, компилирует программы из исходников и прописывает их в `/usr/bin/`. -- `mytoninstaller.py` - Данный скрипт производит настройку валидатора, `mytonctrl` и создание ключей для подключения к валидатору. - -## Режимы установки -Есть два режима установки: `lite` и `full`. Оба они **компилируют** и устанавливают компоненты `TON`. Однако `lite` версия не настраивает и не запускает ноду/валидатор. - -## Установка (Ubuntu) -1. Скачайте и выполните скрипт `install.sh` с нужным вам режимом установки (``). В ходе установки у вас будет несколько раз запрошен пароль суперпользователя. -```sh -wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh -sudo bash install.sh -m -``` - -2. Готово. Можете пробовать запустить программу `mytonctrl`. -```sh -mytonctrl -``` - -## Установка (Debian) -1. Скачайте и выполните скрипт `install.sh` с нужным вам режимом установки. В ходе установки у вас будет несколько раз запрошен пароль суперпользователя. -```sh -wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh -su root -c 'bash install.sh -m ' -``` - -2. Готово. Можете пробовать запустить программу `mytonctrl`. -```sh -mytonctrl -``` - -## Телеметрия -По умолчанию `mytonctrl` отправляет статистику валидатора на сервер https://toncenter.com -Это необходимо для выявления аномалий в сети а так же для быстрого реагирования разработчиков. -Для отключения телеметрии при установке воспользуйтесь флагом `-t`: -```sh -sudo bash install.sh -m -t -``` - -Для отключения телеметрии после установки: -```sh -MyTonCtrl> set sendTelemetry false -``` - -## Веб админка -Для возможности управления нодой/валидатором через браузер нужно установить дополнительный модуль: -`mytonctrl` -> `installer` -> `enable JR` - -Далее нужно создать пароль для подключения: -`mytonctrl` -> `installer` -> `setwebpass` - -Готово. Теперь можно идти на сайт https://tonadmin.org и войти используя свои данные. -git: https://github.com/igroman787/mtc-jsonrpc - -## Локальная копия toncenter -Для того что бы поднять на сервере локальную копию https://toncenter.com нужно установить дополнительный модуль: -`mytonctrl` -> `installer` -> `enable PT` - -Готово. Локальная копия toncenter доступна по адресу `http://:8000` -git: https://github.com/igroman787/pytonv3 - -## Полезные ссылки -1. https://github.com/ton-blockchain/mytonctrl/blob/master/docs/ru/manual-ubuntu.md -2. https://ton.org/docs/ diff --git a/README.md b/README.md index aaf1d762..c3f6fb3c 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ # MyTonCtrl -[Данный текст доступен на русском языке.](README.Ru.md) ## Contents - [What is MyTonCtrl?](#what-is-myttonctrl) +- [MyTonCtrl Documentation](#mytonctrl-documentation) - [Functionality](#functionality) - [List of tested operating systems](#list-of-tested-operating-systems) - [Installation](#installation) @@ -15,7 +15,6 @@ - [Installation modes](#installation-modes) - [Installation for Ubuntu](#installation-for-ubuntu) - [Installation for Debian](#installation-for-debian) -- [MyTonCtrl Documentation](#mytonctrl-documentation) - [Telemetry](#telemetry) - [MyTonCtrl installer mode](#mytonctrl-installer-mode) - [Web admin panel](#web-admin-panel) @@ -24,10 +23,14 @@ # What is MyTonCtrl? -MyTonCtrl is a console application that serves as a convenient wrapper for `fift`, `lite-client`, and `validator-engine-console`. It has been specifically developed to streamline wallet, domain, and validator management tasks on the Linux operating system. +MyTonCtrl is a console application that serves as a convenient wrapper for `fift`, `lite-client`, and `validator-engine-console`. It has been specifically developed for node (validator) management tasks on the Linux operating system. ![MyTonCtrl Status](screens/mytonctrl-status.png) +# MyTonCtrl Documentation + +Mytonctrl's documentation can be found at https://docs.ton.org/participate/run-nodes/mytonctrl. + # Functionality - [x] Show TON network status - [x] Management of local wallets @@ -84,7 +87,8 @@ MyTonCtrl is a console application that serves as a convenient wrapper for `fift - `mytoninstaller.py`: configures the validator and `mytonctrl`; generates validator connection keys. ## Installation modes -There are two installation modes: `lite` and`full`. They both **compile** and install `TON` components. However the `lite` version does not configure or run the node/validator. +There are two installation modes: `liteserver` and `validator`. They both **compile** and install `TON` components and run the node/validator. Use `liteserver` mode if you want to use your node as Liteserver only. +Use `validator` mode if you want to participate in the validator elections (you still can use that node as Liteserver). ## Installation for Ubuntu 1. Download and execute the `install.sh` script in the desired installation mode. During installation the script prompts you for the superuser password several times. @@ -111,17 +115,6 @@ There are two installation modes: `lite` and`full`. They both **compile** and in mytonctrl ``` -# MyTonCtrl Documentation - -This repository contains the following technical documents for MyTonCtrl, categorized by language. Simply click the links below to navigate to the document you're interested in. - -| | FAQ | Import Wallets | Ubuntu Manual | Nominator Pool | -|:-:|:---:|:-------------:|:-------------:|:--------------:| -| **English (EN)** | [Link](./docs/en/FAQ.md) | [Link](./docs/en/import-wallets.md) | [Link](./docs/en/manual-ubuntu.md) | [Link](./docs/en/nominator-pool.md) | -| **Russian (RU)** | [Link](./docs/ru/FAQ.md) | [Link](./docs/ru/import-wallets.md) | [Link](./docs/ru/manual-ubuntu.md) | [Link](./docs/ru/nominator-pool.md) | -| **Traditional Chinese** | [Link](./docs/zh_TW/FAQ.md) | [Link](./docs/zh_TW/import-wallets.md) | [Link](./docs/zh_TW/manual-ubuntu.md) | [Link](./docs/zh_TW/nominator-pool.md) | - - # Telemetry By default, `mytonctrl` sends validator statistics to the https://toncenter.com server. It is necessary to identify network abnormalities, as well as to quickly give feedback to developers. diff --git a/docs/en/FAQ.md b/docs/en/FAQ.md deleted file mode 100644 index a0863b53..00000000 --- a/docs/en/FAQ.md +++ /dev/null @@ -1,124 +0,0 @@ -Here is the optimized version in English: - -# MyTonCtrl Directory Usage - -MyTonCtrl is a wrapper that stores its files in two places: - -1. `~/.local/share/mytonctrl/` - Long-term files such as logs are stored here. -2. `/tmp/mytonctrl/` - Temporary files are stored here. - -MyTonCtrl also includes another script, mytoncore, which in turn stores files in the following locations: - -1. `~/.local/share/mytoncore/` - Permanent files, the main configuration will be stored here. -2. `/tmp/mytoncore/` - Temporary files, parameters used for elections will be saved here. - -MyTonCtrl downloads the source code for itself and the validator into the following directories: - -1. `/usr/src/mytonctrl/` -2. `/usr/src/ton/` - -MyTonCtrl compiles the validator components into the following directory: - -1. `/usr/bin/ton/` - -MyTonCtrl creates a working directory for the validator here: - -1. `/var/ton/` - ---- - -## If MyTonCtrl was installed as root: - -The configurations will be stored differently: - -1. `/usr/local/bin/mytonctrl/` -2. `/usr/local/bin/mytoncore/` - ---- - -## How to remove MyTonCtrl: - -Run the script as an administrator and remove the compiled TON components: - -```bash -sudo bash /usr/src/mytonctrl/scripts/uninstall.sh -sudo rm -rf /usr/bin/ton -``` - -During this process, ensure you have sufficient permissions to delete or modify these files or directories. - - -# Dealing with Errors and Directory Changes with MyTonCtrl - -If you encounter issues running MyTonCtrl as a different user or wish to change the working directory of the validator, this guide provides some solutions. - -## Running MyTonCtrl as Different User - -Running MyTonCtrl as a different user may trigger the following error: - -``` -Error: expected str, bytes or os.PathLike object, not NoneType -``` - -To resolve this, you should run MyTonCtrl as the user who installed it. - -## Changing Validator Working Directory Pre-installation - -If you wish to change the working directory of the validator prior to installation, there are two ways to do so: - -1. **Fork the project** - You can fork the project and make your changes there. Learn how to fork a project with `man git-fork`. -2. **Create a symbolic link** - You can also create a symbolic link with the following command: - - ```bash - ln -s /opt/ton/var/ton - ``` -This command will create a link `/var/ton` that points to `/opt/ton`. - -## Changing Validator Working Directory Post-installation - -If you want to change the working directory of the validator from `/var/ton/` after installation, perform the following steps: - -1. **Stop services** - You will need to stop the services with these commands: - - ```bash - systemctl stop validator - systemctl stop mytoncore - ``` - -2. **Move validator files** - You then need to move the validator files with this command: - - ```bash - mv /var/ton/* /opt/ton/ - ``` - -3. **Update configuration paths** - Replace the paths in the configuration located at `~/.local/share/mytoncore/mytoncore.db`. - -4. **Note on experience** - There is no prior experience with such a transfer, so consider this when moving forward. - -Remember to make sure you have sufficient permissions to make these changes or run these commands. - -# Understanding Validator Status and Restarting Validator in MyTonCtrl - -This document will help you understand how to confirm if MyTonCtrl has become a full validator and how to restart your validator. - -## Checking Validator Status in MyTonCtrl - -You can confirm if your node has become a full validator by checking the following conditions: - -1. **Validator Desynchronization** - The desynchronization of the local validator should be less than 20. -2. **Validator Index** - The validator index should be greater than -1. - -To view the performance factor of your validator, you can use the `vl` command in MyTonCtrl: - -1. Find your validator in the list by its ADNL address (`adnlAddr`). -2. If the `mr` and `wr` coefficients are close to 1, it means that your validator is working correctly. - -## Restarting Your Validator - -If you need to restart your validator, you can do so by running the following command: - -```bash -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. diff --git a/docs/en/controllers.md b/docs/en/controllers.md deleted file mode 100644 index 66b23c90..00000000 --- a/docs/en/controllers.md +++ /dev/null @@ -1,93 +0,0 @@ -# Controllers - -## Launching a Validator in Controller Mode - -1. Prepare the hardware for the validator - 32 virtual cores, 64GB of memory, 1TB SSD, fixed IP address, and 1Gb/s internet speed. - - To maintain network stability, it is recommended to place validators in different locations around the world, rather than concentrating them in a single data center. You can use [this site](https://status.toncenter.com/) to determine the load on various locations. According to the map, there is a high load on data centers in Europe, especially in Finland, Germany, and Paris. Therefore, using providers such as Hetzner and OVH is not recommended. - - > Ensure your hardware meets or exceeds the specified configuration. Running the validator on inappropriate hardware can harm the network and result in penalties. - > Since May 2021, Hetzner has prohibited mining on its servers. This rule currently applies to both PoW and PoS algorithms. Even installing a regular node will be considered a breach of contract. - -2. Install and synchronize **mytonctrl** according to the description in [this instruction](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/en/manual-ubuntu.md) — follow **only** paragraphs 1, 2, and 3. - - You can also refer to this [Video Tutorial](https://docs.ton.org/participate/run-nodes/full-node#installation) for additional help. - -3. Transfer 1 TON to the validator wallet address, which is displayed in the `wl` list. - -4. Use the `aw` command to activate the validator's wallet. - -5. Transfer enough TON to the validator wallet address. - -6. Enable the ton-http-api service: - ``` - mytonctrl -> installer -> enable THA - ``` - Exit installer mode with `Ctrl+D` - -7. Set liquid-staking mode: - - ```bash - enable_mode liquid-staking - set stake null - ``` - -> (!) If you were previously using nominator pools, do not forget to disable them using the `disable_mode nominator-pool` command. - -8Set the liquid pool address, which will lend TON for validation: - ``` - set liquid_pool_addr - ``` - -9. Set the lending parameters that acceptable to you: - ``` - set min_loan 41000 - set max_loan 43000 - set max_interest_percent 1.5 - ``` - - where -* `41000` is the minimum loan amount we are willing to receive from the liquid pool, -* `43000` is the maximum loan amount we are willing to receive from the liquid pool, -* `1.5` 1.5 is the maximum interest rate value for the liquid pool per validation cycle, which we have agreed upon. - -10. Display the annual percentage of profit from the liquid pool: - ``` - calculate_annual_controller_percentage - ``` - -11. Create two controllers with a single command: - - ``` - new_controllers - ``` - -12. Enter `controllers_list` to display the controller addresses: - - ``` - controllers_list - Address Status Balance - kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS active 0.704345 - kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 - ``` - -13. Make a validator deposit in each controller: - - -``` -deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 -deposit_to_controller kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN 10000 -``` - - -where `10000` TON is the deposit amount. - -14. Get approval for the controllers. Each pool may have its own approval issuance policy, check with the operator. - -## Switching a Regular Validator to Controller Operating Mode - -1. Enter `set stake 0` to stop participating in elections. - -2. Wait until both of your deposits have been returned from the Elector. - -3. Follow the instructions under "Launching a Validator in Controller Mode", beginning with **Step 6**. \ No newline at end of file diff --git a/docs/en/import-wallets.md b/docs/en/import-wallets.md deleted file mode 100644 index 0fcac1c9..00000000 --- a/docs/en/import-wallets.md +++ /dev/null @@ -1,33 +0,0 @@ -# Importing Wallets - -MyTonCtrl supports various types of wallet-like contracts, including wallet-v1, wallet-v3, [lockup-wallet](https://github.com/ton-blockchain/lockup-wallet-contract/tree/main/universal), and others. Often, it provides a straightforward way to interact with these contracts. - -## 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 - -If you have a mnemonic phrase (a sequence of 24 words like `tattoo during ...`), follow these steps: - -1. Install Node.js. -2. Clone and install [mnemonic2key](https://github.com/ton-blockchain/mnemonic2key): - ``` - git clone https://github.com/ton-blockchain/mnemonic2key.git - cd mnemonic2key - npm install - ``` -3. Run the following command, replacing `word1`, `word2`... with your mnemonic phrase and `address` with the address of your wallet contract: - ``` - node index.js word1 word2 ... word24 [address] - ``` -4. The script will generate `wallet.pk` and `wallet.addr`. Rename them to `imported_wallet.pk` and `imported_wallet.addr`. -5. Copy both files to the `~/.local/share/mytoncore/wallets/` directory. -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. diff --git a/docs/en/manual-ubuntu.md b/docs/en/manual-ubuntu.md deleted file mode 100644 index aee1ae72..00000000 --- a/docs/en/manual-ubuntu.md +++ /dev/null @@ -1,67 +0,0 @@ -# How to Become a Validator with mytonctrl (v0.2, OS Ubuntu) - -Here are the steps to become a validator using mytonctrl. This example is applicable for the Ubuntu Operating System. - -## 1. Install mytonctrl: - -1. Download the installation script. We recommend installing the tool under your local user account, not as Root. In our example, a local user account is used: - - ```sh - wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh - ``` - - ![wget output](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_wget-ls_ru.png) - -2. Run the installation script as an administrator: - - ```sh - sudo bash install.sh -m full - ``` - -## 2. Conduct an Operability Test: - -1. Run **mytonctrl** from the local user account used for installation in step 1: - - ```sh - mytonctrl - ``` - -2. Check the **mytonctrl** statuses, particularly the following: - -* **mytoncore status**: Should be in green. -* **Local validator status**: Should also be in green. -* **Local validator out of sync**: Initially, a large number is displayed. As soon as the newly created validator connects with other validators, the number will be around 250k. As synchronization progresses, this number decreases. When it falls below 20, the validator is synchronized. - - ![status](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/mytonctrl-status.png) - - -## 3. View the List of Available Wallets - -Check out the list of available wallets. For instance, during the installation of **mytonctrl**, the **validator_wallet_001** wallet is created: - -![wallet list](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-wl_ru.png) - -## 4. Send the Required Number of Coins to the Wallet and Activate It - -To determine the minimum amount of coins required to participate in one election round, head to **tonmon.xyz** > **Participant stakes**. - -* Use the `vas` command to display the history of transfers -* Activate the wallet using the `aw` command - - ![account history](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-vas-aw_ru.png) - -## 5. Your Validator is Now Ready - -**mytoncore** will automatically join the elections. It divides the wallet balance into two parts and uses them as a stake to participate in the elections. You can also manually set the stake size: - -`set stake 50000` — this sets the stake size to 50k coins. If the bet is accepted and our node becomes a validator, the bet can only be withdrawn in the second election (according to the rules of the electorate). - -![setting stake](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-set_ru.png) - -You can also command for help anytime. - -![help command](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-help_ru.png) - -To check **mytoncrl** logs, open `~/.local/share/mytoncore/mytoncore.log` for a local user or `/usr/local/bin/mytoncore/mytoncore.log` for Root. - -![logs](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytoncore-log.png) diff --git a/docs/en/nominator-pool.md b/docs/en/nominator-pool.md deleted file mode 100644 index 1d0dab10..00000000 --- a/docs/en/nominator-pool.md +++ /dev/null @@ -1,118 +0,0 @@ -# Nominator Pool - -## Running the Validator in Nominator Pool Mode - -1. Set up the hardware for the validator - you will need 8 vCPUs, 64GB memory, 1TB SSD, a fixed IP address, and 1Gb/s internet speed. - - For maintaining network stability, it's recommended to distribute validator nodes in different geographical locations worldwide rather than concentrating them in a single data center. You can use [this site](https://status.toncenter.com/) to assess the load of various locations. The map indicates high data center utilization in Europe, especially in Finland, Germany, and Paris. Therefore, using providers such as Hetzner and OVH is not recommended. - - > Ensure your hardware matches or exceeds the specifications above. Running the validator on insufficient hardware negatively impacts the network and could result in penalties. - - > Note that as of May 2021, Hetzner has prohibited mining on its servers, and this ban includes both PoW and PoS algorithms. Even installing a regular node may be considered a violation of their terms of service. - - > **Recommended providers include:** [Amazon](https://aws.amazon.com/), [DigitalOcean](https://www.digitalocean.com/), [Linode](https://www.linode.com/), [Alibaba Cloud](https://alibabacloud.com/), [Latitude](https://www.latitude.sh/). - -2. Install and synchronize **mytonctrl** as described in the guide [here](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/en/manual-ubuntu.md) — follow **only** steps 1, 2, and 3. - - You can also refer to this [Video Instruction](https://ton.org/docs/#/nodes/run-node) for additional help. - -3. Transfer 1 TON to the validator wallet address shown in the `wl` list. - -4. Use the `aw` command to activate your validator wallet. - -5. Activate pool mode: - - ```bash - enable_mode nominator-pool - set stake null - ``` - -6. Create two pools (for even and odd validation rounds): - - ```bash - new_pool p1 0 1 1000 300000 - new_pool p2 0 1 1001 300000 - ``` - - where: - * `p1` is the pool name; - * `0` % is the validator's reward share (e.g., use 40 for 40%); - * `1` is the maximum number of nominators in the pool (should be <= 40); - * `1000` TON is the minimum validator stake (should be >= 1K TON); - * `300000` TON is the minimum nominator stake (should be >= 10K TON); - - > (!) Pool configurations do not have to be identical, you can add 1 to the minimum stake of one pool to make them different. - - > (!) Use https://tonmon.xyz/ to determine the current minimum validator stake. - -7. Type `pools_list` to display pool addresses: - - ```bash - pools_list - Name Status Balance Address - p1 empty 0 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT - p2 empty 0 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL - ``` - -8. Send 1 TON to each pool and activate the pools: - - ```bash - mg validator_wallet_001 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT 1 - mg validator_wallet_001 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL 1 - activate_pool p1 - activate_pool p2 - ``` - -9. Type `pools_list` to display pools: - - ```bash - pools_list - Name Status Balance Address - p1 active 0.731199733 kf98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780v_W - p2 active 0.731199806 kf9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV8UO - ``` - -10. Open each pool via the link "https://tonscan.org/nominator/" and verify pool configurations. - -11. Proceed with the validator deposit to each pool: - - ```bash - deposit_to_pool validator_wallet_001 1005 - deposit_to_pool validator_wallet_001 1005 - ``` - - In these commands, `1005` TON is the deposit amount. Be aware that 1 TON will be deducted by the pool for processing the deposit. - -12. Proceed with the nominator deposit to each pool: - - Visit the pool link (from **Step 9**) and click **ADD STAKE**. - You can also make a deposit using **mytonctrl**, using the following commands: - - ```bash - mg nominator_wallet_001 300001 -C d - mg nominator_wallet_001 300001 -C d - ``` - - > (!) The nominator wallet must be initialized in basechain (workchain 0). - - > (!) Keep in mind that the validator wallet and nominator wallet must be stored separately! The validator wallet should be stored on the server with the validator node to ensure processing of all system transactions. Meanwhile, the nominator wallet should be stored in your cold cryptocurrency wallet. - - > To withdraw a nominator deposit, send a transaction with the comment `w` to the pool address (attach 1 TON to process the transaction). You can also perform this action using **mytonctrl**. - -13. Invite nominators to deposit into your pools. The participation in validation will commence automatically. - - > (!) Ensure that you have at least 200 TON/month in your validator wallet for operation fees. - -## Pool Configuration - -If you're intending to lend to yourself, use `new_pool p1 0 1 1000 300000` (maximum of 1 nominator, 0% validator share). - -If you're creating a pool for numerous nominators, you might use something like this: `new_pool p1 40 40 10000 10000` (maximum of 40 nominators, 40% validator share, minimum participant stakes of 10K TON). - -## Transitioning a Regular Validator to Nominator Pool Mode - -1. Input `set stake 0` to discontinue election participation. - -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. diff --git a/docs/ru/FAQ.md b/docs/ru/FAQ.md deleted file mode 100644 index ddf57bec..00000000 --- a/docs/ru/FAQ.md +++ /dev/null @@ -1,122 +0,0 @@ -# Использование директорий MyTonCtrl - -MyTonCtrl - это оболочка, которая сохраняет свои файлы в двух местах: - -1. `~/.local/share/mytonctrl/` - Долгосрочные файлы, такие как логи, хранятся здесь. -2. `/tmp/mytonctrl/` - Временные файлы хранятся здесь. - -MyTonCtrl также включает другой скрипт, mytoncore, который в свою очередь хранит файлы в следующих местах: - -1. `~/.local/share/mytoncore/` - Постоянные файлы, главная конфигурация будет храниться здесь. -2. `/tmp/mytoncore/` - Временные файлы, параметры, используемые для выборов, будут сохранены здесь. - -MyTonCtrl загружает исходный код для самого себя и валидатора в следующие директории: - -1. `/usr/src/mytonctrl/` -2. `/usr/src/ton/` - -MyTonCtrl компилирует компоненты валидатора в следующую директорию: - -1. `/usr/bin/ton/` - -MyTonCtrl создает рабочую директорию для валидатора здесь: - -1. `/var/ton/` - ---- - -## Если MyTonCtrl был установлен как root: - -Конфигурации будут храниться иначе: - -1. `/usr/local/bin/mytonctrl/` -2. `/usr/local/bin/mytoncore/` - ---- - -## Как удалить MyTonCtrl: - -Запустите скрипт как администратор и удалите скомпилированные компоненты TON: - -```bash -sudo bash /usr/src/mytonctrl/scripts/uninstall.sh -sudo rm -rf /usr/bin/ton -``` - -Во время этого процесса убедитесь, что у вас есть достаточные права для удаления или изменения этих файлов или директорий. - - -# Обработка ошибок и изменение рабочего каталога с MyTonCtrl - -Если вы столкнулись с проблемами при выполнении MyTonCtrl от другого пользователя или хотите изменить рабочий каталог валидатора, эта инструкция предлагает несколько решений. - -## Запуск MyTonCtrl от другого пользователя - -Запуск MyTonCtrl от другого пользователя может вызвать следующую ошибку: - -``` -Error: expected str, bytes or os.PathLike object, not NoneType -``` - -Для ее решения вы должны запустить MyTonCtrl от пользователя, который его установил. - -## Изменение рабочего каталога валидатора перед установкой - -Если вы хотите изменить рабочий каталог валидатора до установки, есть два способа это сделать: - -1. **Сделайте форк проекта** - Вы можете сделать форк проекта и внести свои изменения туда. Узнайте, как сделать форк проекта с помощью `man git-fork`. -2. **Создайте символическую ссылку** - Вы также можете создать символическую ссылку с помощью следующей команды: - - ```bash - ln -s /opt/ton/var/ton - ``` -Эта команда создаст ссылку `/var/ton`, которая указывает на `/opt/ton`. - -## Изменение рабочего каталога валидатора после установки - -Если вы хотите изменить рабочий каталог валидатора с `/var/ton/` после установки, выполните следующие действия: - -1. **Остановите службы** - Вам потребуется остановить службы с помощью этих команд: - - ```bash - systemctl stop validator - systemctl stop mytoncore - ``` - -2. **Переместите файлы валидатора** - Затем вам нужно переместить файлы валидатора с помощью этой команды: - - ```bash - mv /var/ton/* /opt/ton/ - ``` - -3. **Обновите пути в конфигурации** - Замените пути в конфигурации, расположенной в `~/.local/share/mytoncore/mytoncore.db`. - -4. **Примечание об опыте** - Предыдущего опыта такого переноса не было, поэтому учитывайте это при продвижении вперед. - -Не забудьте убедиться, что у вас достаточно прав для внесения этих изменений или выполнения этих команд. - -# Как понять статус валидатора и перезапустить валидатор в MyTonCtrl - -Этот документ поможет вам понять, как подтвердить, стала ли MyTonCtrl полноценным валидатором, и как перезапустить ваш валидатор. - -## Проверка статуса валидатора в MyTonCtrl - -Вы можете подтвердить, что ваша нода стала полноценным валидатором, проверив следующие условия: - -1. **Десинхронизация валидатора** - Десинхронизация локального валидатора должна быть меньше 20. -2. **Индекс валидатора** - Индекс валидатора должен быть больше -1. - -Чтобы просмотреть коэффициент работы своего валидатора, вы можете использовать команду `vl` в MyTonCtrl: - -1. Найдите свой валидатор в списке по его ADNL-адресу (`adnlAddr`). -2. Если коэффициенты `mr` и `wr` близки к 1, это означает, что ваш валидатор работает правильно. - -## Перезапуск вашего валидатора - -Если вам нужно перезапустить ваш валидатор, вы можете сделать это, выполнив следующую команду: - -```bash -systemctl restart validator -``` - -Убедитесь, что у вас есть достаточные права для выполнения этих команд и сделайте необходимые корректировки. Всегда помните о резервном копировании важных данных перед выполнением операций, которые могут потенциально повлиять на ваш валидатор. diff --git a/docs/ru/controllers.md b/docs/ru/controllers.md deleted file mode 100644 index 7f985c21..00000000 --- a/docs/ru/controllers.md +++ /dev/null @@ -1,92 +0,0 @@ -# Контроллеры - -## Запуск валидатора в режиме работы контроллеров - -1. Подготовьте аппаратное обеспечение для валидатора - 32 виртуальных ядер, 64GB памяти, 1TB SSD, фиксированный IP-адрес, скорость интернета 1Gb/s. - - Для поддержания стабильности сети рекомендуется разместить валидаторы в различных местах по всему миру, а не концентрировать их в одном дата-центре. Вы можете использовать [этот сайт](https://status.toncenter.com/) для определения нагрузки на различные места. Согласно карте, высокая нагрузка на дата-центры в Европе, особенно в Финляндии, Германии и Париже. Поэтому использование провайдеров, таких как Hetzner и OVH, не рекомендуется. - - > Ваше оборудование должно соответствовать указанной конфигурации или быть выше. Запуск валидатора на слабом оборудовании негативно влияет на сеть и может привести к штрафам. - - > С мая 2021 года Hetzner запретил майнинг на своих серверах, в настоящее время под это правило попадают алгоритмы PoW и PoS. Установка даже обычного узла будет считаться нарушением условий договора. - -2. Установите и синхронизируйте **mytonctrl** в соответствии с описанием в [этой инструкции](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/ru/manual-ubuntu.md) — следуйте **только** пунктам 1, 2 и 3. - - Вы также можете обратиться к этой [Видеоинструкции](https://docs.ton.org/participate/run-nodes/full-node#installation) для дополнительной помощи. - -3. Переведите 1 TON на адрес кошелька валидатора, который отображается в списке `wl`. - -4. Используйте команду `aw` для активации кошелька валидатора. - -5. Переведите достаточно TON на адрес кошелька валидатора. - -6. Включите ton-http-api службу: - ``` - mytonctrl -> installer -> enable THA - ``` - Выйдите из режима установщика сочетанием клавиш `Ctrl+D` - -7. Активируйте режим работы контроллеров: - - ```bash - enable_mode liquid-staking - set stake null - ``` - -> (!) Если до этого вы использовали номинатор-пулы, не забудьте отключить их использование командой `disable_mode nominator-pool`. - -8. Задайте адрес ликвидного пула, который будет одалживать TON для валидации: - ``` - set liquid_pool_addr - ``` - -9. Задайте параметры кредитования, которые вам подходят: - ``` - set min_loan 41000 - set max_loan 43000 - set max_interest_percent 1.5 - ``` - - где -* `41000` - это минимальная сумма кредита который мы готовы получить у ликвидного пула, -* `43000` - это максимальная сумма кредита который мы готовы получить у ликвидного пула, -* `1.5` - это максимальная процентная ставка ликвидного пула за один цикл валидации на которую мы согласны. - -10. Отобразите годовой процент прибыли от ликвидного пула: - ``` - calculate_annual_controller_percentage - ``` - -11. Создайте два контроллера одной командой: - - ``` - new_controllers - ``` - -12. Введите `controllers_list` чтобы отобразить адреса контроллеров: - - ``` - controllers_list - Address Status Balance - kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS active 0.704345 - kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN active 0.720866 - ``` - -13. Совершите депозит валидатора в каждый контроллер: - - ``` - deposit_to_controller kf89KYOeRPRRDyjt_3bPsz92cKSghRqw64efNr8mT1eeHDaS 10000 - deposit_to_controller kf_lT8QNykLh5PN5ictNX22maiyIf9iK787fXg6nJ_zB-jbN 10000 - ``` - - где `10000` TON - это сумма депозита. - -14. Получите аппрувал контроллеров. У каждого пула может быть своя политика выдачи аппруволов, уточняйте у оператора. - -## Переключение обычного валидатора в режим работы контроллеров - -1. Введите `set stake 0`, чтобы отключить участие в выборах. - -2. Дождитесь, когда оба ваших депозита вернутся от электора. - -3. Следуйте инструкциям "Запуск валидатора в режиме работы контроллеров", начиная с **6-го шага**. diff --git a/docs/ru/import-wallets.md b/docs/ru/import-wallets.md deleted file mode 100644 index f61feab9..00000000 --- a/docs/ru/import-wallets.md +++ /dev/null @@ -1,36 +0,0 @@ -# Импорт кошельков - -MyTonCtrl поддерживает различные типы контрактов, похожих на кошелек: wallet-v1, wallet-v3, [lockup-wallet](https://github.com/ton-blockchain/lockup-wallet-contract/tree/main/universal) и другие. Часто это самый простой способ работы с контрактом. - -## Импорт через приватный ключ - -Если у вас есть приватный ключ, вы можете легко импортировать кошелек. Введите следующую команду в консоль: - -``` -iw <адрес-кошелька> <секретный-ключ-кошелька> -``` - -Здесь `<секретный-ключ-кошелька>` - это ваш приватный ключ в формате base64. - -## Импорт через мнемоническую фразу - -Если у вас есть мнемоническая фраза (последовательность из 24 слов, например, `tattoo during ...`), следуйте этим шагам: - -1. Установите Node.js. -2. Клонируйте и установите [mnemonic2key](https://github.com/ton-blockchain/mnemonic2key): - ``` - git clone https://github.com/ton-blockchain/mnemonic2key.git - cd mnemonic2key - npm install - ``` -3. Запустите следующую команду, замените `word1`, `word2`... на вашу мнемоническую фразу и `address` на адрес вашего контракта кошелька: - ``` - node index.js word1 word2 ... word24 [address] - ``` -4. Скрипт сгенерирует `wallet.pk` и `wallet.addr`. Переименуйте их в `imported_wallet.pk` и `imported_wallet.addr`. -5. Скопируйте оба файла в каталог `~/.local/share/mytoncore/wallets/`. -6. Откройте консоль mytonctrl и перечислите кошельки с помощью команды `wl`. -7. Убедитесь, что кошелек был импортирован и отображает правильный баланс. -8. Теперь вы можете отправить средства с помощью команды `mg`. Введите `mg`, чтобы просмотреть справочную документацию. - -Помните, что при выполнении команд следует заменить заполнители (слова внутри `< >`) на ваши фактические значения. diff --git a/docs/ru/manual-ubuntu.md b/docs/ru/manual-ubuntu.md deleted file mode 100644 index 83307dcb..00000000 --- a/docs/ru/manual-ubuntu.md +++ /dev/null @@ -1,67 +0,0 @@ -# Как стать валидатором с помощью mytonctrl (v0.2, ОС Ubuntu) - -Вот шаги по становлению валидатором с использованием mytonctrl. Этот пример применим для операционной системы Ubuntu. - -## 1. Установка mytonctrl: - -1. Загрузите скрипт установки. Мы рекомендуем устанавливать инструмент под вашей локальной учетной записью пользователя, а не как Root. В нашем примере используется локальная учетная запись пользователя: - - ```sh - wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh - ``` - - ![wget output](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_wget-ls_ru.png) - -2. Запустите скрипт установки как администратор: - - ```sh - sudo bash install.sh -m full - ``` - -## 2. Тест на работоспособность: - -1. Запустите **mytonctrl** с локальной учетной записью пользователя, используемой для установки на шаге 1: - - ```sh - mytonctrl - ``` - -2. Проверьте статусы **mytonctrl**, в частности следующие: - -* **mytoncore status**: должен быть зеленым. -* **Local validator status**: также должен быть зеленым. -* **Local validator out of sync**: Сначала отображается большое число. Как только новый валидатор подключается к другим валидаторам, число будет около 250k. По мере синхронизации это число уменьшается. Когда оно падает ниже 20, валидатор синхронизирован. - - ![status](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/mytonctrl-status.png) - -Смотрим доступные кошельки. Кошелек validator_wallet_001 был создан при установке mytonctrl: - -![wallet list](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-wl_ru.png) - -## 3. Просмотр списка доступных кошельков -Просмотрите список доступных кошельков. В нашем примере кошелек **validator_wallet_001** был создан при установке **mytonctrl**: - -![wallet list](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-wl_ru.png) - -## 4. Отправьте необходимое количество монет в кошелек и активируйте его -Чтобы проверить минимальное количество монет, необходимое для участия в одном раунде выборов, перейдите на **tonmon.xyz** > **Участники ставок**. - -* Команда `vas` отображает историю переводов -* Команда `aw` активирует кошелек - - ![account history](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-vas-aw_ru.png) - -## 5. Теперь ваш валидатор готов к работе -**mytoncore** автоматически присоединяется к выборам. Он делит баланс кошелька на две части и использует их в качестве ставки для участия в выборах. Вы также можете вручную установить размер ставки: - -`set stake 50000` — установить размер ставки в 50k монет. Если ставка принята и наш узел становится валидатором, ставку можно вернуть только на вторых выборах (согласно правилам электората). - -![setting stake](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-set_ru.png) - -Не стесняйтесь обращаться за помощью. - -![help command](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-help_ru.png) - -Для проверки логов **mytoncrl** откройте `~/.local/share/mytoncore/mytoncore.log` для локального пользователя или `/usr/local/bin/mytoncore/mytoncore.log` для Root. - -![logs](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytoncore-log.png) \ No newline at end of file diff --git a/docs/ru/nominator-pool.md b/docs/ru/nominator-pool.md deleted file mode 100644 index 77e88e4c..00000000 --- a/docs/ru/nominator-pool.md +++ /dev/null @@ -1,118 +0,0 @@ -# Номинаторский пул - -## Запуск валидатора в режиме номинаторского пула - -1. Подготовьте аппаратное обеспечение для валидатора - 8 виртуальных ядер, 64GB памяти, 1TB SSD, фиксированный IP-адрес, скорость интернета 1Gb/s. - - Для поддержания стабильности сети рекомендуется разместить валидаторы в различных местах по всему миру, а не концентрировать их в одном дата-центре. Вы можете использовать [этот сайт](https://status.toncenter.com/) для определения нагрузки на различные места. Согласно карте, высокая нагрузка на дата-центры в Европе, особенно в Финляндии, Германии и Париже. Поэтому использование провайдеров, таких как Hetzner и OVH, не рекомендуется. - - > Ваше оборудование должно соответствовать указанной конфигурации или быть выше. Запуск валидатора на слабом оборудовании негативно влияет на сеть и может привести к штрафам. - - > С мая 2021 года Hetzner запретил майнинг на своих серверах, в настоящее время под это правило попадают алгоритмы PoW и PoS. Установка даже обычного узла будет считаться нарушением условий договора. - - > **Рекомендуемые провайдеры:** [Amazon](https://aws.amazon.com/), [DigitalOcean](https://www.digitalocean.com/), [Linode](https://www.linode.com/), [Alibaba Cloud](https://alibabacloud.com/), [Latitude](https://www.latitude.sh/). - -2. Установите и синхронизируйте **mytonctrl** в соответствии с описанием в [этой инструкции](https://github.com/ton-blockchain/mytonctrl/blob/master/docs/ru/manual-ubuntu.md) — следуйте **только** пунктам 1, 2 и 3. - - Вы также можете обратиться к этой [Видеоинструкции](https://ton.org/docs/#/nodes/run-node) для дополнительной помощи. - -3. Переведите 1 TON на адрес кошелька валидатора, который отображается в списке `wl`. - -4. Используйте команду `aw` для активации кошелька валидатора. - -5. Активируйте режим пула: - - ```bash - enable_mode nominator-pool - set stake null - ``` - -6. Создайте два пула (для четного и нечетного раунда проверки): - - ``` - new_pool p1 0 1 1000 300000 - new_pool p2 0 1 1001 300000 - ``` - - где - * `p1` — имя пула; - * `0` % — это доля вознаграждения валидатора (например, используйте 40 для 40%); - * `1` - максимальное количество номинаторов в пуле (должно быть <= 40); - * `1000` TON — минимальная ставка валидатора (должна быть >= 1K TON); - * `300000` TON – минимальная ставка номинатора (должна быть >= 10K TON); - - > (!) Конфигурации пулов не должны быть идентичными, вы можете добавить 1 к минимальной ставке одного пула, чтобы сделать их разными. - - > (!) Используйте https://tonmon.xyz/, чтобы определить текущую минимальную ставку валидатора. - -7. Введите `pools_list` чтобы отобразить адреса пулов: - - ``` - pools_list - Name Status Balance Address - p1 empty 0 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT - p2 empty 0 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL - ``` - -8. Отправьте по 1 TON в каждый пул и активируйте пулы: - - ``` - mg validator_wallet_001 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT 1 - mg validator_wallet_001 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL 1 - activate_pool p1 - activate_pool p2 - ``` - -9. Введите `pools_list` чтобы отобразить адреса пулов: - - ``` - pools_list - Name Status Balance Address - p1 active 0.731199733 kf98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780v_W - p2 active 0.731199806 kf9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV8UO - ``` - -10. Откройте каждый пул по ссылке "https://tonscan.org/nominator/" и проверьте конфигурацию пулов. - -11. Совершите депозит валидатора в каждый пул: - - ```bash - deposit_to_pool validator_wallet_001 1005 - deposit_to_pool validator_wallet_001 1005 - ``` - - где `1005` TON - это сумма депозита. Обратите внимание, что пул вычтет 1 TON за обработку депозита. - -12. Совершите депозит номинатора в каждый пул: - - Перейдите по ссылке пула (из **шага 9**) и нажмите **ADD STAKE**. - Вы также можете сделать депозит, используя **mytonctrl**, с помощью следующих команд: - - ```bash - mg nominator_wallet_001 300001 -C d - mg nominator_wallet_001 300001 -C d - ``` - - > (!) Кошелек номинатора должен быть инициализирован в basechain (workchain 0). - - > (!) Обратите внимание, что кошельки валидатора и номинатора должны храниться отдельно! Кошелек валидатора должен храниться на сервере с узлом валидатора для обработки всех системных транзакций. Кошелек номинатора следует хранить в вашем холодном криптовалютном кошельке. - - > Чтобы снять депозит номинатора, отправьте транзакцию с комментарием `w` на адрес пула (должен быть прикреплен 1 TON для обработки транзакции). Вы также можете сделать это с помощью **mytonctrl**. - -13. Пригласите номинаторов сделать депозиты в ваши пулы. Участие в валидации начнется автоматически. - - > (!) Убедитесь, что у вас на кошельке валидатора есть как минимум 200 TON в месяц на операционные расходы. - -## Настройка пулов - -Если вы хотите давать в долг самому себе, то используйте `new_pool p1 0 1 1000 300000` (максимум 1 номинант, 0% доли валидатора). - -Если вы создаете пул для многих номинантов, то используйте что-то вроде этого: `new_pool p1 40 40 10000 10000` (максимум 40 номинантов, 40% доли валидатора, минимальная ставка участника 10K TON). - -## Переключение обычного валидатора в режим номинаторского пула - -1. Введите `set stake 0`, чтобы отключить участие в выборах. - -2. Дождитесь, когда оба ваших депозита вернутся от электора. - -3. Следуйте инструкциям "Запуск валидатора в режиме номинантского пула", начиная с **4-го шага**. diff --git a/docs/ru/ton-storage-provider.md b/docs/ru/ton-storage-provider.md deleted file mode 100644 index 3500b5b3..00000000 --- a/docs/ru/ton-storage-provider.md +++ /dev/null @@ -1,32 +0,0 @@ -# TON storage provider - -MyTonCtrl поддерживает установку дополнительных компонентов таких как `TON storage` и `TON storage provider`. С их помощью вы можете хранить пользовательские файлы у себя на сервере и получать за это вознаграждение. - -## Установка дополнительных компонентов - -Войдите в MyTonCtrl -``` -mytonctrl -``` - -Затем войдите в режим установщика -``` -installer -``` - -После включите нужный функционал TON storage provider: -``` -enable TSP -``` - -## Активация контракта провайдера - -В ходе установки дополнительных компонетов был создан специальный кошелек провайдера `provider_wallet_001` откуда будут отправляться доказательства и куда будет приходить награда. -Для его работы сначала нужно пополнить этот кошелек на 1 монету и активировать его командой внутри MyTonCtrl, в ходе которого он так же зарегистрируется в списке провайдеров: -``` -activate_ton_storage_provider -``` - -## Панель управления TON storage provider - -TODO diff --git a/docs/zh_TW/FAQ.md b/docs/zh_TW/FAQ.md deleted file mode 100644 index 067902ed..00000000 --- a/docs/zh_TW/FAQ.md +++ /dev/null @@ -1,121 +0,0 @@ -# MyTonCtrl 使用的目錄 - -MyTonCtrl 是一個包裝器,會在兩個地方儲存檔案: - -1. `~/.local/share/mytonctrl/` - 儲存長期檔案,如日誌檔 -2. `/tmp/mytonctrl/` - 儲存臨時檔案 - -MyTonCtrl 也包含了另一個腳本 mytoncore,它將檔案儲存到以下位置: - -1. `~/.local/share/mytoncore/` - 持久檔案,主要的設定檔會儲存在這裡 -2. `/tmp/mytoncore/` - 臨時檔案,選舉使用的參數將會保存在此 - -MyTonCtrl 會將自身和驗證者的源碼下載到以下資料夾: - -1. `/usr/src/mytonctrl/` -2. `/usr/src/ton/` - -MyTonCtrl 會將驗證者的組件編譯到以下資料夾: - -1. `/usr/bin/ton/` - -MyTonCtrl 會在這裡建立一個驗證者工作的資料夾: - -1. `/var/ton/` - ---- - -## 若 MyTonCtrl 以 root 使用者安裝: - -那麼,設定檔會以不同的方式存放: - -1. `/usr/local/bin/mytonctrl/` -2. `/usr/local/bin/mytoncore/` - ---- - -## 如何移除 MyTonCtrl: - -以管理員身份執行腳本並移除已編譯的 TON 組件: - -```bash -sudo bash /usr/src/mytonctrl/scripts/uninstall.sh -sudo rm -rf /usr/bin/ton -``` - -在這個過程中,確保你有足夠的權限來刪除或更改這些檔案或目錄。 - -# 處理錯誤和更改 MyTonCtrl 的工作目錄 - -如果您在使用不同的使用者執行 MyTonCtrl 時遇到問題,或者您想要在安裝前更改驗證者的工作目錄,以下的指南可以提供幾種解決方案。 - -## 以不同的使用者執行 MyTonCtrl - -當以不同的使用者執行 MyTonCtrl 時,可能會出現以下錯誤: - -``` -Error: expected str, bytes or os.PathLike object, not NoneType -``` - -要解決此問題,您需要以安裝 MyTonCtrl 的使用者執行程式。 - -## 在安裝前更改驗證者的工作目錄 - -如果您想在安裝前更改驗證者的工作目錄,有兩種方式可以達成: - -1. **分叉專案** - 您可以分叉專案並在其中進行修改。查看 `man git-fork` 指令以瞭解如何進行分叉操作。 -2. **創建符號連結** - 您也可以使用以下指令創建一個符號連結: - - ```bash - ln -s /opt/ton/var/ton - ``` -此指令會創建一個名為 `/var/ton` 的連結,導向 `/opt/ton` 目錄。 - -## 在安裝後更改驗證者的工作目錄 - -如果您希望在安裝後將驗證者的工作目錄從 `/var/ton/` 改為其他目錄,請按照以下步驟進行: - -1. **停止服務** - 使用以下指令停止相關服務: - - ```bash - systemctl stop validator - systemctl stop mytoncore - ``` - -2. **移動驗證者的檔案** - 接著使用以下指令將驗證者的檔案移至新的目錄: - - ```bash - mv /var/ton/* /opt/ton/ - ``` - -3. **更改配置中的路徑** - 將 `~/.local/share/mytoncore/mytoncore.db` 中的路徑替換為新的路徑。 - -4. **注意事項** - 之前並未有過如此的轉移經驗,所以進行此操作時請小心。 - -請確認您擁有足夠的權限來執行這些修改和指令。 - -# 如何在 MyTonCtrl 中確認驗證者狀態並重啟驗證者 - -本文檔將幫助你了解如何確認 MyTonCtrl 是否已成為全功能驗證者,以及如何重啟你的驗證者。 - -## 在 MyTonCtrl 中確認驗證者狀態 - -你可以透過以下條件來確認你的節點是否已成為全功能驗證者: - -1. **驗證者的異步狀態** - 本地驗證者的異步狀態應該小於 20。 -2. **驗證者的索引** - 驗證者的索引應該大於 -1。 - -你可以透過 MyTonCtrl 的 `vl` 命令查看驗證者的工作率: - -1. 在列表中按照其 ADNL 地址(`adnlAddr`)找到你的驗證者。 -2. 如果 `mr` 和 `wr` 的係數接近 1,則表示你的驗證者運行正常。 - -## 重啟你的驗證者 - -如果你需要重啟你的驗證者,可以執行以下命令: - -```bash -systemctl restart validator -``` - -請確保你具有執行這些命令的適當權限,並進行必要的調整。在執行可能影響你的驗證者的操作之前,請始終記得備份重要數據。 diff --git a/docs/zh_TW/import-wallets.md b/docs/zh_TW/import-wallets.md deleted file mode 100644 index 1e199e1c..00000000 --- a/docs/zh_TW/import-wallets.md +++ /dev/null @@ -1,36 +0,0 @@ -# 匯入錢包 - -MyTonCtrl支援多種類型的類似錢包的合約,包括wallet-v1,wallet-v3,[lockup-wallet](https://github.com/ton-blockchain/lockup-wallet-contract/tree/main/universal)等等。通常,這是處理這些合約的最簡單方法。 - -## 使用私鑰匯入 - -如果你知道私鑰,你只需要在控制台輸入以下指令: - -``` -iw -``` - -在此,`` 是以base64格式的私鑰。 - -## 使用助記詞匯入 - -如果你知道助記詞短語(像是由24個單詞組成的短語,例如 `tattoo during ...`),請執行以下步驟: - -1. 安裝Node.js。 -2. 複製並安裝 [mnemonic2key](https://github.com/ton-blockchain/mnemonic2key): - ``` - git clone https://github.com/ton-blockchain/mnemonic2key.git - cd mnemonic2key - npm install - ``` -3. 執行以下命令,其中 `word1`,`word2` ... 是你的助記詞短語,`address` 是你的錢包合約地址: - ``` - node index.js word1 word2 ... word24 [address] - ``` -4. 腳本將生成 `wallet.pk` 和 `wallet.addr`,將它們重命名為 `imported_wallet.pk` 和 `imported_wallet.addr`。 -5. 將這兩個檔案複製到 `~/.local/share/mytoncore/wallets/` 目錄。 -6. 開啟mytonctrl控制台,並使用 `wl` 命令列出錢包。 -7. 確認錢包已經匯入並且餘額正確。 -8. 現在你可以使用 `mg` 命令發送金錢(輸入 `mg` 可查看使用說明)。 - -在執行命令時,記得將尖括號內的佔位符(例如 ``、``)替換為實際的值。 diff --git a/docs/zh_TW/manual-ubuntu.md b/docs/zh_TW/manual-ubuntu.md deleted file mode 100644 index aa6a98b7..00000000 --- a/docs/zh_TW/manual-ubuntu.md +++ /dev/null @@ -1,67 +0,0 @@ -# 如何使用 mytonctrl 成為驗證者 (v0.2, Ubuntu操作系統) - -以下為使用 mytonctrl 成為驗證者的步驟。此範例適用於Ubuntu操作系統。 - -## 1. 安裝 mytonctrl: - -1. 下載安裝腳本。我們建議在您的本地用戶帳戶下安裝該工具,而非 Root。在我們的示例中,使用的是本地用戶帳戶: - - ```sh - wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh - ``` - - ![wget output](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_wget-ls_ru.png) - -2. 以管理員身份運行安裝腳本: - - ```sh - sudo bash install.sh -m full - ``` - -## 2. 操作測試: - -1. 從在第一步中用於安裝的本地用戶帳戶運行 **mytonctrl**: - - ```sh - mytonctrl - ``` - -2. 檢查 **mytonctrl** 的狀態,特別是以下幾點: - -* **mytoncore status**:應為綠色。 -* **Local validator status**:應為綠色。 -* **Local validator out of sync**:首次顯示出一個大數字。新創建的驗證者一旦與其他驗證者聯繫,該數字約為250k。隨著同步的進行,這個數字會減少。當它降至20以下時,驗證者就同步了。 - - ![status](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/mytonctrl-status.png) - - -## 3. 查看可用錢包列表 - -檢查可用的錢包列表。例如,在安裝 **mytonctrl** 時,會創建 **validator_wallet_001** 錢包: - -![wallet list](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-wl_ru.png) - -## 4. 向錢包發送所需數量的幣並激活它 - -要確定參與一輪選舉所需的最小幣數,請轉到 **tonmon.xyz** > **參與者賭注**。 - -* 使用 `vas` 命令顯示轉賬歷史 -* 使用 `aw` 命令激活錢包 - - ![account history](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-vas-aw_ru.png) - -## 5. 現在你的驗證人準備好了 - -**mytoncore** 將自動加入選舉。它將錢包餘額分為兩部分,並將它們作為賭注參與選舉。您也可以手動設定賭注大小: - -`set stake 50000` — 這將賭注大小設定為50k幣。如果賭注被接受,並且我們的節點成為驗證人,則只能在第二次選舉中撤回賭注(根據選民的規則)。 - -![setting stake](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-set_ru.png) - -您也可以隨時命令求助。 - -![help command](https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/screens/manual-ubuntu_mytonctrl-help_ru.png) - -要檢查 **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) diff --git a/docs/zh_TW/nominator-pool.md b/docs/zh_TW/nominator-pool.md deleted file mode 100644 index fd107ca6..00000000 --- a/docs/zh_TW/nominator-pool.md +++ /dev/null @@ -1,117 +0,0 @@ -# Nominator pool - -## 在提名人池模式下運行驗證人 - -1. 為驗證人準備硬體 - 8個虛擬 CPU、64GB 內存、1TB SSD、固定 IP 地址、1Gb/s 的網路速度。 - - 為了維護網路穩定性,建議將驗證節點分布在世界不同地點,而不是集中在一個數據中心。可以使用 https://status.toncenter.com/ 確定位置的負載。根據地圖,你可以看到歐洲、芬蘭、德國和巴黎的數據中心使用率高。因此,我們不建議使用像 Hetzner 和 OVH 這樣的提供商。 - - > 你的硬體必須符合指定的配置或更高。不要在弱硬體上運行驗證器 - 這將對網路產生負面影響,並將對你進行罰款。 - - > 由於 2021 年 5 月,Hetzner 已經禁止在其伺服器上挖礦,目前 PoW 和 PoS 算法都適用於此規則。即使安裝了常規節點,也將被視為違反協議條款。 - - > **推薦的提供商:** [amazon](https://aws.amazon.com/), [digitalocean](https://www.digitalocean.com/), [linode](https://www.linode.com/), [alibaba cloud](https://alibabacloud.com/), [latitude](https://www.latitude.sh/). - -2. 安裝並同步 **mytonctrl**,如 https://github.com/ton-blockchain/mytonctrl/blob/master/docs/zh_TW/manual-ubuntu.md 中描述的那樣,**僅**執行步驟1、2和3。 - - [視頻指導](https://ton.org/docs/#/nodes/run-node)。 - -3. 將 1 TON 發送到顯示在 `wl` 列表中的驗證人錢包地址。 - -4. 輸入 `aw` 以啟動驗證人錢包。 - -5. 建立兩個池子(對於偶數和奇數的驗證輪次): - - ``` - new_pool p1 0 1 1000 300000 - new_pool p2 0 1 1001 300000 - ``` - 其中 - * `p1` 是池名稱; - * `0` % 是驗證人的獎勵份額(例如,對於 40% 使用 40); - * `1` 是池中的最大提名人數量(應 <= 40); - * `1000` TON 是最低驗證人的股份(應 >= 1K TON); - * `300000` TON 是最低提名人的股份(應 >= 10K TON); - - > (!) 池的配置不必相同,你可以向其中一個池的最小股份增加 1 以使它們不同。 - - > (!) 使用 https://tonmon.xyz/ 確定當前最小驗證人股份。 - -6. 輸入 `pools_list` 顯示池地址: - - ``` - pools_list - Name Status Balance Address - p1 empty 0 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT - p2 empty 0 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL - ``` - -7. 向每個池發送 1 TON 並激活池: - - ``` - mg validator_wallet_001 0f98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780qIT 1 - mg validator_wallet_001 0f9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV5jL 1 - activate_pool p1 - activate_pool p2 - ``` - -8. 輸入 `pools_list` 來顯示池: - - ``` - pools_list - Name Status Balance Address - p1 active 0.731199733 kf98YhXA9wnr0d5XRXT-I2yH54nyQzn0tuAYC4FunT780v_W - p2 active 0.731199806 kf9qtmnzs2-PumMisKDmv6KNjNfOMDQG70mQdp-BcAhnV8UO - ``` - -9. 打開每個池的連結 "https://tonscan.org/nominator/" 並驗證池配置。 - -10. 向每個池進行驗證者存款: - - ```bash - deposit_to_pool validator_wallet_001 1005 - deposit_to_pool validator_wallet_001 1005 - ``` - - 其中 `1005` TON 是存款金額。請注意,池會扣除 1 TON 用於處理存款。 - -11. 向每個池進行提名人存款: - - 轉到池鏈接(**第9步**)並單擊 **ADD STAKE**。 - 您也可以使用 **mytonctrl** 進行存款,使用以下命令進行。 - - ```bash - mg nominator_wallet_001 300001 -C d - mg nominator_wallet_001 300001 -C d - ``` - - > (!) 提名人錢包必須在 basechain (workchain 0) 初始化。 - - > (!) 請注意,驗證者錢包和提名人錢包必須單獨存放!驗證者錢包存放在具有驗證者節點的服務器上,以確保所有系統交易的處理。提名人錢包存放在您的冷加密貨幣錢包中。 - - > 如需撤回提名人存款,發送附註 `w` 的交易到池地址(必須附加 1 TON 以處理交易)。您也可以使用 **mytonctrl** 進行此操作。 - -12. 啟動池模式: - - ```bash - set usePool true - set stake null - ``` - -13. 邀請提名人向您的池存款。驗證參與將自動開始。 - - > (!) 您需要在驗證者錢包上至少有 200 TON/月的操作費用。 - -## 設定池 - -如果你打算借給自己,則使用 `new_pool p1 0 1 1000 300000`(最大1個提名人,驗證者的份額為0%)。 - -如果你為許多提名人創建池,則可以使用類似以下的設定:`new_pool p1 40 40 10000 10000`(最多40個提名人,驗證者的份額為40%,最低參與者的賭注為10K TON)。 - -## 將一般驗證者轉換為提名人池模式 - -1. 輸入 `set stake 0` 來停止參加選舉。 - -2. 等待你的兩個賭注從選民那裡返回。 - -3. 從**第四步**開始,按照"在提名人池模式下運行驗證者"的步驟進行操作。 From a506e53b732aad45d346f55d8d8e31e6e4975131 Mon Sep 17 00:00:00 2001 From: yungwine Date: Fri, 19 Jul 2024 14:52:37 +0800 Subject: [PATCH 231/236] update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c3f6fb3c..c577d8b4 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,8 @@ Mytonctrl's documentation can be found at https://docs.ton.org/participate/run-n There are two installation modes: `liteserver` and `validator`. They both **compile** and install `TON` components and run the node/validator. Use `liteserver` mode if you want to use your node as Liteserver only. Use `validator` mode if you want to participate in the validator elections (you still can use that node as Liteserver). +Learn more about node types: https://docs.ton.org/participate/nodes/node-types + ## Installation for Ubuntu 1. Download and execute the `install.sh` script in the desired installation mode. During installation the script prompts you for the superuser password several times. ```sh From 7c8a5c9f9f02e2a8c267aa93b9eb391c4157a3c9 Mon Sep 17 00:00:00 2001 From: yungwine Date: Mon, 5 Aug 2024 11:27:36 +0800 Subject: [PATCH 232/236] fix incorrect warning for --state-ttl changing --- mytonctrl/mytonctrl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index 47e06721..ba60f84b 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -388,7 +388,7 @@ def Upgrade(ton, args): try: from mytoninstaller.mytoninstaller import set_node_argument, get_node_args node_args = get_node_args() - if node_args['--state-ttl'] == '604800': + if node_args.get('--state-ttl') == '604800': set_node_argument(ton.local, ["--state-ttl", "-d"]) except Exception as e: color_print(f"{{red}}Failed to set node argument: {e} {{endc}}") From c34a459023c2510363926b1813a83980a58fd39c Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 6 Aug 2024 14:18:31 +0800 Subject: [PATCH 233/236] check validator wallet status before activating pool --- modules/__init__.py | 1 + modules/nominator_pool.py | 2 ++ modules/single_pool.py | 1 + mytoncore/mytoncore.py | 27 +++++++++++++++++++-------- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/modules/__init__.py b/modules/__init__.py index 298302b0..625ecc79 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -34,6 +34,7 @@ class Setting: 'stake': Setting('validator', None, 'Stake amount'), 'stakePercent': Setting('validator', 99, 'Stake percent if `stake` is null'), 'isSlashing': Setting('validator', None, 'Create complaints to validators'), + 'walletName': Setting('validator', None, 'Wallet name'), 'maxFactor': Setting('validator', None, 'Param send to Elector. if null will be taken from 17 config param'), 'participateBeforeEnd': Setting('validator', None, 'Amount of seconds before start of round to participate'), 'liquid_pool_addr': Setting('liquid-staking', None, 'Liquid staking pool address'), diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index a5adcc4b..3ca8647b 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -62,6 +62,8 @@ def do_activate_pool(self, pool, ex=True): elif account.status == "active": self.local.add_log("do_activate_pool warning: account status is active", "warning") else: + validator_wallet = self.ton.GetValidatorWallet() + self.ton.check_account_status(validator_wallet.addrB64) self.ton.SendFile(pool.bocFilePath, pool, timeout=False, remove=False) #end define diff --git a/modules/single_pool.py b/modules/single_pool.py index d2721c5a..7e33a260 100644 --- a/modules/single_pool.py +++ b/modules/single_pool.py @@ -51,6 +51,7 @@ def do_activate_single_pool(self, pool): self.local.add_log("start activate_single_pool function", "debug") boc_mode = "--with-init" validator_wallet = self.ton.GetValidatorWallet() + self.ton.check_account_status(validator_wallet.addrB64) result_file_path = self.ton.SignBocWithWallet(validator_wallet, pool.bocFilePath, pool.addrB64_init, 1, boc_mode=boc_mode) self.ton.SendFile(result_file_path, validator_wallet) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index 098d6ec9..fffede66 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1180,9 +1180,7 @@ def SignBocWithWallet(self, wallet, boc_path, dest, coins, **kwargs): # Balance checking account = self.GetAccount(wallet.addrB64) - if account.balance < coins + 0.1: - raise Exception("Wallet balance is less than requested coins") - #end if + self.check_account_balance(account, coins + 0.1) # Bounceable checking destAccount = self.GetAccount(dest) @@ -1864,6 +1862,22 @@ def GetWalletId(self, wallet): return subwallet #end define + def check_account_balance(self, account, coins): + if not isinstance(account, Account): + account = self.GetAccount(account) + if account.balance < coins: + raise Exception(f"Wallet {account.addrB64} balance is less than requested coins. Balance: {account.balance}, requested amount: {coins} (need {coins - account.balance} more)") + # end if + # end define + + def check_account_status(self, account): + if not isinstance(account, Account): + account = self.GetAccount(account) + if account.status != "active": + raise Exception(f"Wallet {account.addrB64} account is uninitialized") + # end if + # end define + def MoveCoins(self, wallet, dest, coins, **kwargs): self.local.add_log("start MoveCoins function", "debug") flags = kwargs.get("flags", list()) @@ -1884,11 +1898,8 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): # Balance checking account = self.GetAccount(wallet.addrB64) - if account.balance < coins + 0.1: - raise Exception("Wallet balance is less than requested coins") - if account.status != "active": - raise Exception("Wallet account is uninitialized") - #end if + self.check_account_balance(account, coins + 0.1) + self.check_account_status(account) # Bounceable checking destAccount = self.GetAccount(dest) From 968437a4b598974a5c72d78c7343cf0fd45d0f54 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 6 Aug 2024 14:20:32 +0800 Subject: [PATCH 234/236] fixes fix exceptions rename method fix name --- modules/__init__.py | 2 +- modules/nominator_pool.py | 2 +- modules/single_pool.py | 2 +- mytoncore/mytoncore.py | 11 +++++++---- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/__init__.py b/modules/__init__.py index 625ecc79..8b92c260 100644 --- a/modules/__init__.py +++ b/modules/__init__.py @@ -34,7 +34,7 @@ class Setting: 'stake': Setting('validator', None, 'Stake amount'), 'stakePercent': Setting('validator', 99, 'Stake percent if `stake` is null'), 'isSlashing': Setting('validator', None, 'Create complaints to validators'), - 'walletName': Setting('validator', None, 'Wallet name'), + 'validatorWalletName': Setting('validator', 'wallet_001', 'Validator\'s wallet name'), 'maxFactor': Setting('validator', None, 'Param send to Elector. if null will be taken from 17 config param'), 'participateBeforeEnd': Setting('validator', None, 'Amount of seconds before start of round to participate'), 'liquid_pool_addr': Setting('liquid-staking', None, 'Liquid staking pool address'), diff --git a/modules/nominator_pool.py b/modules/nominator_pool.py index 3ca8647b..14f4fbdd 100644 --- a/modules/nominator_pool.py +++ b/modules/nominator_pool.py @@ -63,7 +63,7 @@ def do_activate_pool(self, pool, ex=True): self.local.add_log("do_activate_pool warning: account status is active", "warning") else: validator_wallet = self.ton.GetValidatorWallet() - self.ton.check_account_status(validator_wallet.addrB64) + self.ton.check_account_active(validator_wallet.addrB64) self.ton.SendFile(pool.bocFilePath, pool, timeout=False, remove=False) #end define diff --git a/modules/single_pool.py b/modules/single_pool.py index 7e33a260..5b5c6e2b 100644 --- a/modules/single_pool.py +++ b/modules/single_pool.py @@ -51,7 +51,7 @@ def do_activate_single_pool(self, pool): self.local.add_log("start activate_single_pool function", "debug") boc_mode = "--with-init" validator_wallet = self.ton.GetValidatorWallet() - self.ton.check_account_status(validator_wallet.addrB64) + self.ton.check_account_active(validator_wallet.addrB64) result_file_path = self.ton.SignBocWithWallet(validator_wallet, pool.bocFilePath, pool.addrB64_init, 1, boc_mode=boc_mode) self.ton.SendFile(result_file_path, validator_wallet) diff --git a/mytoncore/mytoncore.py b/mytoncore/mytoncore.py index fffede66..ed643083 100644 --- a/mytoncore/mytoncore.py +++ b/mytoncore/mytoncore.py @@ -1866,15 +1866,18 @@ def check_account_balance(self, account, coins): if not isinstance(account, Account): account = self.GetAccount(account) if account.balance < coins: - raise Exception(f"Wallet {account.addrB64} balance is less than requested coins. Balance: {account.balance}, requested amount: {coins} (need {coins - account.balance} more)") + raise Exception(f"Account {account.addrB64} balance is less than requested coins. Balance: {account.balance}, requested amount: {coins} (need {coins - account.balance} more)") # end if # end define - def check_account_status(self, account): + def check_account_active(self, account): if not isinstance(account, Account): + address = account account = self.GetAccount(account) + else: + address = account.addrB64 if account.status != "active": - raise Exception(f"Wallet {account.addrB64} account is uninitialized") + raise Exception(f"Account {address} account is uninitialized") # end if # end define @@ -1899,7 +1902,7 @@ def MoveCoins(self, wallet, dest, coins, **kwargs): # Balance checking account = self.GetAccount(wallet.addrB64) self.check_account_balance(account, coins + 0.1) - self.check_account_status(account) + self.check_account_active(account) # Bounceable checking destAccount = self.GetAccount(dest) From ed83c22ccdf09caa0fff98737fd28f45cc058d45 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 6 Aug 2024 19:32:56 +0800 Subject: [PATCH 235/236] delete unused files form mtc1 --- custom_overlays.py | 191 ------------------------------------- scripts/set_archive_ttl.py | 38 -------- scripts/set_state_ttl.py | 30 ------ 3 files changed, 259 deletions(-) delete mode 100644 custom_overlays.py delete mode 100644 scripts/set_archive_ttl.py delete mode 100644 scripts/set_state_ttl.py diff --git a/custom_overlays.py b/custom_overlays.py deleted file mode 100644 index 03cad4fa..00000000 --- a/custom_overlays.py +++ /dev/null @@ -1,191 +0,0 @@ -import base64 -import json -import requests - -from mypylib.mypylib import color_print - - -def hex2base64(h): - b = bytes.fromhex(h) - b64 = base64.b64encode(b) - s = b64.decode("utf-8") - return s - - -def parse_config(name: str, config: dict, vset: list = None): - """ - Converts config to validator-console friendly format - :param name: custom overlay name - :param config: config - :param vset: list of validators adnl addresses, can be None if `@validators` not in config - :return: - """ - result = { - "name": name, - "nodes": [] - } - for k, v in config.items(): - if k == '@validators' and v: - if vset is None: - raise Exception("Validators set is not defined but @validators is in config") - for v_adnl in vset: - result["nodes"].append({ - "adnl_id": hex2base64(v_adnl), - "msg_sender": False, - }) - else: - result["nodes"].append({ - "adnl_id": hex2base64(k), - "msg_sender": v["msg_sender"], - }) - if v["msg_sender"]: - result["nodes"][-1]["msg_sender_priority"] = v["msg_sender_priority"] - return result - - -def add_custom_overlay(args): - from mytonctrl import ton, local - if len(args) != 2: - color_print("{red}Bad args. Usage:{endc} add_custom_overlay ") - return - path = args[1] - with open(path, 'r') as f: - config = json.load(f) - ton.set_custom_overlay(args[0], config) - if '@validators' in config: - print('Dynamic overlay will be added within 1 minute') - else: - result = add_custom_overlay_to_vc(local, ton, parse_config(args[0], config)) - if not result: - print('Failed to add overlay to validator console') - color_print("add_custom_overlay - {red}ERROR{endc}") - return - color_print("add_custom_overlay - {green}OK{endc}") - - -def list_custom_overlays(args): - from mytonctrl import ton - if not ton.get_custom_overlays(): - color_print("{red}No custom overlays{endc}") - return - for k, v in ton.get_custom_overlays().items(): - color_print(f"Custom overlay {{bold}}{k}{{endc}}:") - print(json.dumps(v, indent=4)) - - -def delete_custom_overlay(args): - from mytonctrl import ton - if len(args) != 1: - color_print("{red}Bad args. Usage:{endc} delete_custom_overlay ") - return - if '@validators' in ton.get_custom_overlays().get(args[0], {}): - ton.delete_custom_overlay(args[0]) - print('Dynamic overlay will be deleted within 1 minute') - else: - ton.delete_custom_overlay(args[0]) - result = delete_custom_overlay_from_vc(ton, args[0]) - if not result: - print('Failed to delete overlay from validator console') - color_print("delete_custom_overlay - {red}ERROR{endc}") - return - color_print("delete_custom_overlay - {green}OK{endc}") - - -def check_node_eligible_for_custom_overlay(ton, config: dict): - vconfig = ton.GetValidatorConfig() - my_adnls = vconfig.adnl - node_adnls = [i["adnl_id"] for i in config["nodes"]] - for adnl in my_adnls: - if adnl.id in node_adnls: - return True - return False - - -def delete_custom_overlay_from_vc(ton, name: str): - result = ton.validatorConsole.Run(f"delcustomoverlay {name}") - return 'success' in result - - -def add_custom_overlay_to_vc(local, ton, config: dict): - if not check_node_eligible_for_custom_overlay(ton, config): - local.add_log(f"Node has no adnl address required for custom overlay {config.get('name')}", "debug") - return False - local.add_log(f"Adding custom overlay {config.get('name')}", "debug") - path = ton.tempDir + f'/custom_overlay_{config["name"]}.json' - with open(path, 'w') as f: - json.dump(config, f) - result = ton.validatorConsole.Run(f"addcustomoverlay {path}") - return 'success' in result - - -def custom_overlays(local, ton): - config = get_default_custom_overlay(local, ton) - if config is not None: - ton.set_custom_overlay('default', config) - deploy_custom_overlays(local, ton) - - -def deploy_custom_overlays(local, ton): - result = ton.validatorConsole.Run("showcustomoverlays") - if 'unknown command' in result: - return # node old version - names = [] - for line in result.split('\n'): - if line.startswith('Overlay'): - names.append(line.split(' ')[1].replace('"', '').replace(':', '')) - - config34 = ton.GetConfig34() - current_el_id = config34['startWorkTime'] - current_vset = [i["adnlAddr"] for i in config34['validators']] - - config36 = ton.GetConfig36() - next_el_id = config36['startWorkTime'] if config36['validators'] else 0 - next_vset = [i["adnlAddr"] for i in config36['validators']] - - for name in names: - # check that overlay still exists in mtc db - pure_name = name - suffix = name.split('_')[-1] - if suffix.startswith('elid') and suffix.split('elid')[-1].isdigit(): # probably election id - pure_name = '_'.join(name.split('_')[:-1]) - el_id = int(suffix.split('elid')[-1]) - if el_id not in (current_el_id, next_el_id): - local.add_log(f"Overlay {name} is not in current or next election, deleting", "debug") - delete_custom_overlay_from_vc(ton, name) # delete overlay if election id is not in current or next election - continue - - if pure_name not in ton.get_custom_overlays(): - local.add_log(f"Overlay {name} ({pure_name}) is not in mtc db, deleting", "debug") - delete_custom_overlay_from_vc(ton, name) # delete overlay if it's not in mtc db - - for name, config in ton.get_custom_overlays().items(): - if name in names: - continue - if '@validators' in config: - new_name = name + '_elid' + str(current_el_id) - if new_name not in names: - node_config = parse_config(new_name, config, current_vset) - add_custom_overlay_to_vc(local, ton, node_config) - - if next_el_id != 0: - new_name = name + '_elid' + str(next_el_id) - if new_name not in names: - node_config = parse_config(new_name, config, next_vset) - add_custom_overlay_to_vc(local, ton, node_config) - else: - node_config = parse_config(name, config) - add_custom_overlay_to_vc(local, ton, node_config) - - -def get_default_custom_overlay(local, ton): - if not local.db.get('useDefaultCustomOverlays', True): - return None - network = ton.GetNetworkName() - default_url = 'https://ton-blockchain.github.io/fallback_custom_overlays.json' - url = local.db.get('defaultCustomOverlaysUrl', default_url) - resp = requests.get(url) - if resp.status_code != 200: - local.add_log(f"Failed to get default custom overlays from {url}", "error") - return None - config = resp.json() - return config.get(network) diff --git a/scripts/set_archive_ttl.py b/scripts/set_archive_ttl.py deleted file mode 100644 index f11fd436..00000000 --- a/scripts/set_archive_ttl.py +++ /dev/null @@ -1,38 +0,0 @@ -import subprocess -import sys - -with open('/etc/systemd/system/validator.service', 'r') as file: - service = file.read() - - -for line in service.split('\n'): - if line.startswith('ExecStart'): - exec_start = line - break - - -if '--archive-ttl' in exec_start: - print('Archive TTL is already set') - sys.exit(100) - -default_command = 'ExecStart = /usr/bin/ton/validator-engine/validator-engine --threads --daemonize --global-config /usr/bin/ton/global.config.json --db /var/ton-work/db/ --logname /var/ton-work/log --state-ttl 604800 --verbosity' - -# ExecStart = /usr/bin/ton/validator-engine/validator-engine --threads 31 --daemonize --global-config /usr/bin/ton/global.config.json --db /var/ton-work/db/ --logname /var/ton-work/log --state-ttl 604800 --verbosity 1 - -t = exec_start.split(' ') -t.pop(t.index('--threads') + 1) # pop threads value since it's different for each node -t.pop(t.index('--verbosity') + 1) # pop verbosity value - -if ' '.join(t) != default_command: - print('ExecStart is not default. Please set archive-ttl manually in `/etc/systemd/system/validator.service`.') - sys.exit(101) - -archive_ttl = sys.argv[1] - -new_exec_start = exec_start + f' --archive-ttl {archive_ttl}' - -with open('/etc/systemd/system/validator.service', 'w') as file: - file.write(service.replace(exec_start, new_exec_start)) - -subprocess.run(['systemctl', 'daemon-reload']) -subprocess.run(['systemctl', 'restart', 'validator']) diff --git a/scripts/set_state_ttl.py b/scripts/set_state_ttl.py deleted file mode 100644 index 4838fe29..00000000 --- a/scripts/set_state_ttl.py +++ /dev/null @@ -1,30 +0,0 @@ -import subprocess -import sys - -with open('/etc/systemd/system/validator.service', 'r') as file: - service = file.read() - - -for line in service.split('\n'): - if line.startswith('ExecStart'): - exec_start = line - break - - -if exec_start.split(' ')[2] != '/usr/bin/ton/validator-engine/validator-engine': - raise Exception('Invalid node start command in service file') - - -if '--state-ttl 604800' not in exec_start: - print('No state-ttl or custom one found in ExecStart') - sys.exit(0) - -new_exec_start = exec_start.replace('--state-ttl 604800', '') - -with open('/etc/systemd/system/validator.service', 'w') as file: - file.write(service.replace(exec_start, new_exec_start)) - -subprocess.run(['systemctl', 'daemon-reload']) -subprocess.run(['systemctl', 'restart', 'validator']) - -print('Removed state-ttl from service file.') From 371e1a7619c506926d1f23b19a5caa7dfebc9e19 Mon Sep 17 00:00:00 2001 From: yungwine Date: Tue, 6 Aug 2024 23:46:28 +0800 Subject: [PATCH 236/236] change branch names --- mytonctrl/migrations/roll_back_001.sh | 2 +- mytonctrl/mytonctrl.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mytonctrl/migrations/roll_back_001.sh b/mytonctrl/migrations/roll_back_001.sh index ca35c8e7..eab2869c 100644 --- a/mytonctrl/migrations/roll_back_001.sh +++ b/mytonctrl/migrations/roll_back_001.sh @@ -2,7 +2,7 @@ pip3 uninstall -y mytonctrl cd /usr/src rm -rf mytonctrl -git clone --recursive https://github.com/ton-blockchain/mytonctrl +git clone --recursive -b mytonctrl1 https://github.com/ton-blockchain/mytonctrl echo "Updating /usr/bin/mytonctrl" echo "/usr/bin/python3 /usr/src/mytonctrl/mytonctrl.py $@" > /usr/bin/mytonctrl diff --git a/mytonctrl/mytonctrl.py b/mytonctrl/mytonctrl.py index ba60f84b..33224717 100755 --- a/mytonctrl/mytonctrl.py +++ b/mytonctrl/mytonctrl.py @@ -344,7 +344,7 @@ def check_branch_exists(author, repo, branch): def Update(local, args): repo = "mytonctrl" - author, repo, branch = check_git(args, repo, "update", default_branch='mytonctrl2') + author, repo, branch = check_git(args, repo, "update") # Run script update_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/update.sh')