Skip to content

Commit

Permalink
Merge pull request #403 from ton-blockchain/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
igroman787 authored Dec 12, 2024
2 parents e0ead70 + 5177df7 commit 7caf031
Show file tree
Hide file tree
Showing 22 changed files with 325 additions and 179 deletions.
4 changes: 3 additions & 1 deletion modules/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ class Setting:
'debug': Setting(None, False, 'Debug mtc console mode. Prints Traceback on errors'),
'subscribe_tg_channel': Setting('validator', False, 'Disables warning about subscribing to the `TON STATUS` channel'),
'BotToken': Setting('alert-bot', None, 'Alerting Telegram bot token'),
'ChatId': Setting('alert-bot', None, 'Alerting Telegram chat id')
'ChatId': Setting('alert-bot', None, 'Alerting Telegram chat id'),
'auto_backup': Setting('validator', None, 'Make validator backup every election'),
'auto_backup_path': Setting('validator', '/tmp/mytoncore/auto_backups/', 'Path to store auto-backups'),
}


Expand Down
12 changes: 10 additions & 2 deletions modules/alert_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ class Alert:
"out_of_sync": Alert(
"critical",
"Node is out of sync on {sync} sec.",
0
300
),
"service_down": Alert(
"critical",
"validator.service is down.",
0
300
),
"adnl_connection_failed": Alert(
"high",
Expand Down Expand Up @@ -83,6 +83,7 @@ def __init__(self, ton, local, *args, **kwargs):
self.validator_module = None
self.inited = False
self.hostname = None
self.ip = None
self.token = None
self.chat_id = None
self.last_db_check = 0
Expand Down Expand Up @@ -113,6 +114,7 @@ def send_alert(self, alert_name: str, *args, **kwargs):
❗️ <b>MyTonCtrl Alert {alert_name}</b> ❗️
Hostname: <code>{self.hostname}</code>
Node IP: <code>{self.ip}</code>
Time: <code>{time_}</code> (<code>{int(time.time())}</code>)
Severity: <code>{alert.severity}</code>
Expand Down Expand Up @@ -140,6 +142,7 @@ def init(self):
from modules.validator import ValidatorModule
self.validator_module = ValidatorModule(self.ton, self.local)
self.hostname = get_hostname()
self.ip = self.ton.get_validator_engine_ip()
self.set_global_vars()
self.inited = True

Expand Down Expand Up @@ -189,6 +192,8 @@ def print_alerts(self, args):
print_table(table)

def test_alert(self, args):
if not self.inited:
self.init()
self.send_message('Test alert')

def check_db_usage(self):
Expand All @@ -204,6 +209,9 @@ def check_db_usage(self):
def check_validator_wallet_balance(self):
if not self.ton.using_validator():
return
validator_status = self.ton.GetValidatorStatus()
if not validator_status.is_working or validator_status.out_of_sync >= 20:
return
validator_wallet = self.ton.GetValidatorWallet()
validator_account = self.ton.GetAccount(validator_wallet.addrB64)
if validator_account.balance < 10:
Expand Down
80 changes: 80 additions & 0 deletions modules/backups.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import os
import shutil
import subprocess
import time

import pkg_resources

from modules.module import MtcModule
from mypylib.mypylib import color_print, ip2int, run_as_root, parse
from mytoninstaller.config import get_own_ip


class BackupModule(MtcModule):

def create_keyring(self, dir_name):
keyring_dir = dir_name + '/keyring'
self.ton.validatorConsole.Run(f'exportallprivatekeys {keyring_dir}')

def create_tmp_ton_dir(self):
result = self.ton.validatorConsole.Run("getconfig")
text = parse(result, "---------", "--------")
dir_name = self.ton.tempDir + f'/ton_backup_{int(time.time() * 1000)}'
dir_name_db = dir_name + '/db'
os.makedirs(dir_name_db)
with open(dir_name_db + '/config.json', 'w') as f:
f.write(text)
self.create_keyring(dir_name_db)
return dir_name

def create_backup(self, args):
if len(args) > 1:
color_print("{red}Bad args. Usage:{endc} create_backup [filename]")
return
tmp_dir = self.create_tmp_ton_dir()
command_args = ["-m", self.ton.local.buffer.my_work_dir, "-t", tmp_dir]
if len(args) == 1:
command_args += ["-d", args[0]]
backup_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/create_backup.sh')
process = subprocess.run(["bash", backup_script_path] + command_args, timeout=5)

if process.returncode == 0:
color_print("create_backup - {green}OK{endc}")
else:
color_print("create_backup - {red}Error{endc}")
shutil.rmtree(tmp_dir)
return process.returncode
# end define

def restore_backup(self, args):
if len(args) == 0 or len(args) > 2:
color_print("{red}Bad args. Usage:{endc} restore_backup <filename> [-y]")
return
if '-y' not in args:
res = input(
f'This action will overwrite existing configuration with contents of backup archive, please make sure that donor node is not in operation prior to this action. Proceed [y/n]')
if res.lower() != 'y':
print('aborted.')
return
else:
args.pop(args.index('-y'))
print('Before proceeding, mtc will create a backup of current configuration.')
try:
self.create_backup([])
except:
color_print("{red}Could not create backup{endc}")

ip = str(ip2int(get_own_ip()))
command_args = ["-m", self.ton.local.buffer.my_work_dir, "-n", args[0], "-i", ip]

restore_script_path = pkg_resources.resource_filename('mytonctrl', 'scripts/restore_backup.sh')
if run_as_root(["bash", restore_script_path] + command_args) == 0:
color_print("restore_backup - {green}OK{endc}")
self.local.exit()
else:
color_print("restore_backup - {red}Error{endc}")
# end define

def add_console_commands(self, console):
console.AddItem("create_backup", self.create_backup, self.local.translate("create_backup_cmd"))
console.AddItem("restore_backup", self.restore_backup, self.local.translate("restore_backup_cmd"))
38 changes: 38 additions & 0 deletions modules/nominator_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,45 @@ def update_validator_set(self, args):
self.ton.PoolUpdateValidatorSet(pool_addr, wallet)
color_print("UpdateValidatorSet - {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 <pool-addr> <amount>")
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 <pool-addr> <amount>")
return
self.do_withdraw_from_pool(pool_addr, amount)
color_print("WithdrawFromPool - {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("update_validator_set", self.update_validator_set, self.local.translate("update_validator_set_cmd"))
console.AddItem("withdraw_from_pool", self.withdraw_from_pool, self.local.translate("withdraw_from_pool_cmd"))
console.AddItem("deposit_to_pool", self.deposit_to_pool, self.local.translate("deposit_to_pool_cmd"))
38 changes: 0 additions & 38 deletions modules/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,45 +58,7 @@ 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 <pool-addr> <amount>")
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 <pool-addr> <amount>")
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"))
5 changes: 3 additions & 2 deletions modules/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,13 +313,14 @@ def print_validator_list(self, args):
print(text)
else:
table = list()
table += [["id", "ADNL", "Pubkey", "Wallet", "Efficiency", "Online"]]
table += [["id", "ADNL", "Pubkey", "Wallet", "Stake", "Efficiency", "Online"]]
for i, item in enumerate(data):
adnl = item.get("adnlAddr")
pubkey = item.get("pubkey")
walletAddr = item.get("walletAddr")
efficiency = item.get("efficiency")
online = item.get("online")
stake = item.get("stake")
if "adnl" not in args:
adnl = self.reduct(adnl)
if "pubkey" not in args:
Expand All @@ -332,7 +333,7 @@ def print_validator_list(self, args):
online = bcolors.green_text("true")
if not online:
online = bcolors.red_text("false")
table += [[str(i), adnl, pubkey, walletAddr, efficiency, online]]
table += [[str(i), adnl, pubkey, walletAddr, stake, efficiency, online]]
print_table(table)
# end define

Expand Down
50 changes: 43 additions & 7 deletions mytoncore/mytoncore.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
get_timestamp,
timestamp2datetime,
dec2hex,
Dict
Dict, int2ip
)


Expand Down Expand Up @@ -115,6 +115,7 @@ def CheckConfigFile(self, fift, liteClient):
self.local.add_log("Restoring the configuration file", "info")
args = ["cp", backup_path, mconfig_path]
subprocess.run(args)
self.dbFile = mconfig_path
self.Refresh()
elif os.path.isfile(backup_path) == False:
self.local.add_log("Create backup config file", "info")
Expand Down Expand Up @@ -1454,21 +1455,47 @@ def ElectionEntry(self, args=None):
self.local.add_log("ElectionEntry completed. Start work time: " + str(startWorkTime))

self.clear_tmp()
self.make_backup(startWorkTime)

#end define

def clear_tmp(self):
def clear_dir(self, dir_name):
start = time.time()
count = 0
week_ago = 60 * 60 * 24 * 7
dir = self.tempDir
for f in os.listdir(dir):
ts = os.path.getmtime(os.path.join(dir, f))
for f in os.listdir(dir_name):
ts = os.path.getmtime(os.path.join(dir_name, f))
if ts < time.time() - week_ago:
count += 1
os.remove(os.path.join(dir, f))
if os.path.isfile(os.path.join(dir_name, f)):
os.remove(os.path.join(dir_name, f))
self.local.add_log(f"Removed {count} old files from {dir_name} directory for {int(time.time() - start)} seconds", "info")

def clear_tmp(self):
self.clear_dir(self.tempDir)

self.local.add_log(f"Removed {count} old files from tmp dir for {int(time.time() - start)} seconds", "info")
def make_backup(self, election_id: str):
if not self.local.db.get("auto_backup"):
return
from modules.backups import BackupModule
module = BackupModule(self, self.local)
args = []
name = f"/mytonctrl_backup_elid{election_id}.zip"
backups_dir = self.tempDir + "/auto_backups"
if self.local.db.get("auto_backup_path"):
backups_dir = self.local.db.get("auto_backup_path")
os.makedirs(backups_dir, exist_ok=True)
args.append(backups_dir + name)
self.clear_dir(backups_dir)
exit_code = module.create_backup(args)
if exit_code != 0:
self.local.add_log(f"Backup failed with exit code {exit_code}", "error")
# try one more time
exit_code = module.create_backup(args)
if exit_code != 0:
self.local.add_log(f"Backup failed with exit code {exit_code}", "error")
if exit_code == 0:
self.local.add_log(f"Backup created successfully", "info")

def GetValidatorKeyByTime(self, startWorkTime, endWorkTime):
self.local.add_log("start GetValidatorKeyByTime function", "debug")
Expand Down Expand Up @@ -2490,6 +2517,8 @@ def GetValidatorsList(self, past=False, fast=False, start=None, end=None):
validator["efficiency"] = round(validator["wr"] * 100, 2)
if saveElectionEntries and adnlAddr in saveElectionEntries:
validator["walletAddr"] = saveElectionEntries[adnlAddr]["walletAddr"]
validator["stake"] = saveElectionEntries[adnlAddr].get("stake")
validator["stake"] = int(validator["stake"]) if validator["stake"] else None
#end for

# Set buffer
Expand Down Expand Up @@ -3791,6 +3820,13 @@ def GetNetworkName(self):
return "unknown"
#end define

def get_validator_engine_ip(self):
try:
config = self.GetValidatorConfig()
return int2ip(config['addrs'][0]['ip'])
except:
return None

def GetFunctionBuffer(self, name, timeout=10):
timestamp = get_timestamp()
buff = self.local.buffer.get(name)
Expand Down
Loading

0 comments on commit 7caf031

Please sign in to comment.