Skip to content

Commit d5a8869

Browse files
authored
Merge pull request #347 from ton-blockchain/efficiency
Efficiency
2 parents 7e90e26 + c3ec6a0 commit d5a8869

File tree

6 files changed

+130
-34
lines changed

6 files changed

+130
-34
lines changed

modules/validator.py

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
from mypylib.mypylib import color_print
1+
from mypylib.mypylib import color_print, get_timestamp
22
from modules.module import MtcModule
3+
from mytonctrl.utils import timestamp2utcdatetime, GetColorInt
34

45

56
class ValidatorModule(MtcModule):
@@ -32,7 +33,52 @@ def vote_complaint(self, args):
3233
self.ton.VoteComplaint(election_id, complaint_hash)
3334
color_print("VoteComplaint - {green}OK{endc}")
3435

36+
def find_myself(self, validators: list) -> dict:
37+
adnl_addr = self.ton.GetAdnlAddr()
38+
for validator in validators:
39+
if validator.get("adnlAddr") == adnl_addr:
40+
return validator
41+
return None
42+
43+
def check_efficiency(self, args):
44+
self.local.add_log("start GetValidatorEfficiency function", "debug")
45+
previous_validators = self.ton.GetValidatorsList(past=True)
46+
validators = self.ton.GetValidatorsList()
47+
validator = self.find_myself(previous_validators)
48+
config32 = self.ton.GetConfig32()
49+
config34 = self.ton.GetConfig34()
50+
color_print("{cyan}===[ Validator efficiency ]==={endc}")
51+
if validator:
52+
efficiency = 100 if validator.efficiency > 100 else validator.efficiency
53+
color_efficiency = GetColorInt(efficiency, 90, logic="more", ending="%")
54+
created = validator.blocks_created
55+
expected = validator.blocks_expected
56+
start_time = timestamp2utcdatetime(config32.startWorkTime)
57+
end_time = timestamp2utcdatetime(config32.endWorkTime)
58+
color_print(f"Previous round efficiency: {color_efficiency} {{yellow}}({created} blocks created / {expected} blocks expected){{endc}}")
59+
color_print(f"Previous round time: {{yellow}}from {start_time} to {end_time}{{endc}}")
60+
else:
61+
print("Couldn't find this validator in the past round")
62+
validator = self.find_myself(validators)
63+
if validator:
64+
efficiency = 100 if validator.efficiency > 100 else validator.efficiency
65+
color_efficiency = GetColorInt(efficiency, 90, logic="more", ending="%")
66+
created = validator.blocks_created
67+
expected = validator.blocks_expected
68+
start_time = timestamp2utcdatetime(config34.startWorkTime)
69+
end_time = timestamp2utcdatetime(int(get_timestamp()))
70+
if validator.is_masterchain == False and efficiency < 90:
71+
print("Your validator index is greater than 100.")
72+
print("Efficiency before the validation round is complete may be inaccurate and not displayed.")
73+
else:
74+
color_print(f"Current round efficiency: {color_efficiency} {{yellow}}({created} blocks created / {expected} blocks expected){{endc}}")
75+
color_print(f"Current round time: {{green}}from {start_time} to {end_time}{{endc}}")
76+
else:
77+
print("Couldn't find this validator in the current round")
78+
# end define
79+
3580
def add_console_commands(self, console):
3681
console.AddItem("vo", self.vote_offer, self.local.translate("vo_cmd"))
3782
console.AddItem("ve", self.vote_election_entry, self.local.translate("ve_cmd"))
3883
console.AddItem("vc", self.vote_complaint, self.local.translate("vc_cmd"))
84+
console.AddItem("check_ef", self.check_efficiency, self.local.translate("check_ef_cmd"))

mytoncore/functions.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ def Slashing(local, ton):
521521
def save_past_events(local, ton):
522522
local.try_function(ton.GetElectionEntries)
523523
local.try_function(ton.GetComplaints)
524+
local.try_function(ton.GetValidatorsList, args=[True]) # cache past vl
524525

525526

526527
def ScanLiteServers(local, ton):

mytoncore/mytoncore.py

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -913,9 +913,10 @@ def GetConfig32(self):
913913
#end if
914914

915915
self.local.add_log("start GetConfig32 function", "debug")
916-
config32 = dict()
916+
config32 = Dict()
917917
result = self.liteClient.Run("getconfig 32")
918918
config32["totalValidators"] = int(parse(result, "total:", ' '))
919+
config32["mainValidators"] = int(parse(result, "main:", ' '))
919920
config32["startWorkTime"] = int(parse(result, "utime_since:", ' '))
920921
config32["endWorkTime"] = int(parse(result, "utime_until:", ' '))
921922
lines = result.split('\n')
@@ -928,7 +929,7 @@ def GetConfig32(self):
928929
validatorWeight = int(parse(line, "weight:", ' '))
929930
except ValueError:
930931
validatorWeight = int(parse(line, "weight:", ')'))
931-
buff = dict()
932+
buff = Dict()
932933
buff["adnlAddr"] = validatorAdnlAddr
933934
buff["pubkey"] = pubkey
934935
buff["weight"] = validatorWeight
@@ -949,9 +950,10 @@ def GetConfig34(self):
949950
#end if
950951

951952
self.local.add_log("start GetConfig34 function", "debug")
952-
config34 = dict()
953+
config34 = Dict()
953954
result = self.liteClient.Run("getconfig 34")
954955
config34["totalValidators"] = int(parse(result, "total:", ' '))
956+
config34["mainValidators"] = int(parse(result, "main:", ' '))
955957
config34["startWorkTime"] = int(parse(result, "utime_since:", ' '))
956958
config34["endWorkTime"] = int(parse(result, "utime_until:", ' '))
957959
config34["totalWeight"] = int(parse(result, "total_weight:", ' '))
@@ -965,7 +967,7 @@ def GetConfig34(self):
965967
validatorWeight = int(parse(line, "weight:", ' '))
966968
except ValueError:
967969
validatorWeight = int(parse(line, "weight:", ')'))
968-
buff = dict()
970+
buff = Dict()
969971
buff["adnlAddr"] = validatorAdnlAddr
970972
buff["pubkey"] = pubkey
971973
buff["weight"] = validatorWeight
@@ -2320,6 +2322,19 @@ def GetSaveComplaints(self):
23202322
return saveComplaints
23212323
#end define
23222324

2325+
def GetSaveVl(self):
2326+
timestamp = get_timestamp()
2327+
save_vl = self.local.db.get("saveValidatorsLoad")
2328+
if save_vl is None:
2329+
save_vl = dict()
2330+
self.local.db["saveValidatorsLoad"] = save_vl
2331+
for key, item in list(save_vl.items()):
2332+
diff_time = timestamp - int(key)
2333+
if diff_time > 172800: # 48 hours
2334+
save_vl.pop(key)
2335+
return save_vl
2336+
#end define
2337+
23232338
def GetAdnlFromPubkey(self, inputPubkey):
23242339
config32 = self.GetConfig32()
23252340
validators = config32["validators"]
@@ -2467,12 +2482,17 @@ def get_valid_complaints(self, complaints: dict, election_id: int):
24672482
pseudohash = pubkey + str(election_id)
24682483
if pseudohash == complaint['pseudohash']:
24692484
exists = True
2485+
vid = item['id']
24702486
break
24712487

24722488
if not exists:
24732489
self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint info was not found, probably it's wrong", "info")
24742490
continue
24752491

2492+
if vid >= config32['mainValidators']:
2493+
self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint created for non masterchain validator", "info")
2494+
continue
2495+
24762496
# check complaint fine value
24772497
if complaint['suggestedFine'] != 101: # https://github.com/ton-blockchain/ton/blob/5847897b3758bc9ea85af38e7be8fc867e4c133a/lite-client/lite-client.cpp#L3708
24782498
self.local.add_log(f"complaint {complaint['hash_hex']} declined: complaint fine value is {complaint['suggestedFine']} ton", "info")
@@ -2486,7 +2506,7 @@ def get_valid_complaints(self, complaints: dict, election_id: int):
24862506

24872507
def GetOnlineValidators(self):
24882508
onlineValidators = list()
2489-
validators = self.GetValidatorsList()
2509+
validators = self.GetValidatorsList(fast=True)
24902510
for validator in validators:
24912511
online = validator.get("online")
24922512
if online is True:
@@ -2503,7 +2523,6 @@ def GetValidatorsLoad(self, start, end, saveCompFiles=False) -> dict:
25032523
if buff:
25042524
return buff
25052525
#end if
2506-
25072526
text = "start GetValidatorsLoad function ({}, {})".format(start, end)
25082527
self.local.add_log(text, "debug")
25092528
if saveCompFiles is True:
@@ -2579,7 +2598,7 @@ def GetValidatorsLoad(self, start, end, saveCompFiles=False) -> dict:
25792598
return data
25802599
#end define
25812600

2582-
def GetValidatorsList(self, past=False):
2601+
def GetValidatorsList(self, past=False, fast=False):
25832602
# Get buffer
25842603
bname = "validatorsList" + str(past)
25852604
buff = self.GetFunctionBuffer(bname, timeout=60)
@@ -2589,13 +2608,21 @@ def GetValidatorsList(self, past=False):
25892608

25902609
timestamp = get_timestamp()
25912610
end = timestamp - 60
2592-
start = end - 2000
25932611
config = self.GetConfig34()
2612+
if fast:
2613+
start = end - 1000
2614+
else:
2615+
start = config.get("startWorkTime")
25942616
if past:
25952617
config = self.GetConfig32()
25962618
start = config.get("startWorkTime")
25972619
end = config.get("endWorkTime") - 60
2620+
save_vl = self.GetSaveVl()
2621+
start_str = str(start)
2622+
if start_str in save_vl:
2623+
return save_vl[start_str]
25982624
#end if
2625+
25992626
validatorsLoad = self.GetValidatorsLoad(start, end)
26002627
validators = config["validators"]
26012628
electionId = config.get("startWorkTime")
@@ -2608,12 +2635,22 @@ def GetValidatorsList(self, past=False):
26082635
validator["wr"] = validatorsLoad[vid]["wr"]
26092636
validator["efficiency"] = validatorsLoad[vid]["efficiency"]
26102637
validator["online"] = validatorsLoad[vid]["online"]
2638+
validator["blocks_created"] = validatorsLoad[vid]["masterBlocksCreated"] + validatorsLoad[vid]["workBlocksCreated"]
2639+
validator["blocks_expected"] = validatorsLoad[vid]["masterBlocksExpected"] + validatorsLoad[vid]["workBlocksExpected"]
2640+
validator["is_masterchain"] = False
2641+
if vid < config["mainValidators"]:
2642+
validator["is_masterchain"] = True
2643+
if not validator["is_masterchain"]:
2644+
validator["efficiency"] = round(validator["wr"] * 100, 2)
26112645
if saveElectionEntries and adnlAddr in saveElectionEntries:
26122646
validator["walletAddr"] = saveElectionEntries[adnlAddr]["walletAddr"]
26132647
#end for
26142648

26152649
# Set buffer
26162650
self.SetFunctionBuffer(bname, validators)
2651+
if past:
2652+
save_vl = self.GetSaveVl()
2653+
save_vl[start] = validators
26172654
return validators
26182655
#end define
26192656

@@ -2625,6 +2662,7 @@ def CheckValidators(self, start, end):
26252662
data = self.GetValidatorsLoad(start, end, saveCompFiles=True)
26262663
fullElectorAddr = self.GetFullElectorAddr()
26272664
wallet = self.GetValidatorWallet(mode="vote")
2665+
config = self.GetConfig32()
26282666

26292667
# Check wallet and balance
26302668
if wallet is None:
@@ -2642,6 +2680,8 @@ def CheckValidators(self, start, end):
26422680
pseudohash = pubkey + str(electionId)
26432681
if pseudohash in valid_complaints:
26442682
continue
2683+
if item['id'] >= config['mainValidators']: # do not create complaints for non-masterchain validators
2684+
continue
26452685
# Create complaint
26462686
fileName = self.remove_proofs_from_complaint(fileName)
26472687
fileName = self.PrepareComplaint(electionId, fileName)
@@ -3463,7 +3503,7 @@ def ImportCertificate(self, pubkey, fileName):
34633503

34643504
def GetValidatorsWalletsList(self):
34653505
result = list()
3466-
vl = self.GetValidatorsList()
3506+
vl = self.GetValidatorsList(fast=True)
34673507
for item in vl:
34683508
walletAddr = item["walletAddr"]
34693509
result.append(walletAddr)

mytonctrl/mytonctrl.py

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
)
4343
from mytoncore.telemetry import is_host_virtual
4444
from mytonctrl.migrate import run_migrations
45-
from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime, fix_git_config
45+
from mytonctrl.utils import GetItemFromList, timestamp2utcdatetime, fix_git_config, GetColorInt
4646

4747
import sys, getopt, os
4848

@@ -578,7 +578,7 @@ def PrintStatus(local, ton, args):
578578

579579
if opt != "fast":
580580
onlineValidators = ton.GetOnlineValidators()
581-
validator_efficiency = ton.GetValidatorEfficiency()
581+
# validator_efficiency = ton.GetValidatorEfficiency()
582582
if onlineValidators:
583583
onlineValidators = len(onlineValidators)
584584

@@ -761,7 +761,7 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid
761761

762762
color_print(local.translate("local_status_head"))
763763
print(validatorIndex_text)
764-
print(validatorEfficiency_text)
764+
# print(validatorEfficiency_text)
765765
print(adnlAddr_text)
766766
print(fullnode_adnl_text)
767767
print(walletAddr_text)
@@ -781,22 +781,6 @@ def PrintLocalStatus(local, adnlAddr, validatorIndex, validatorEfficiency, valid
781781
print()
782782
#end define
783783

784-
def GetColorInt(data, border, logic, ending=None):
785-
if data is None:
786-
result = "n/a"
787-
elif logic == "more":
788-
if data >= border:
789-
result = bcolors.green_text(data, ending)
790-
else:
791-
result = bcolors.red_text(data, ending)
792-
elif logic == "less":
793-
if data <= border:
794-
result = bcolors.green_text(data, ending)
795-
else:
796-
result = bcolors.red_text(data, ending)
797-
return result
798-
#end define
799-
800784
def GetColorStatus(input):
801785
if input == True:
802786
result = bcolors.green_text("working")
@@ -873,6 +857,7 @@ def PrintTimes(local, rootWorkchainEnabledTime_int, startWorkTime, oldStartWorkT
873857
print(startNextElectionTime_text)
874858
#end define
875859

860+
876861
def GetColorTime(datetime, timestamp):
877862
newTimestamp = get_timestamp()
878863
if timestamp > newTimestamp:
@@ -1344,7 +1329,8 @@ def PrintElectionEntriesList(ton, args):
13441329

13451330
def PrintValidatorList(ton, args):
13461331
past = "past" in args
1347-
data = ton.GetValidatorsList(past=past)
1332+
fast = "fast" in args
1333+
data = ton.GetValidatorsList(past=past, fast=fast)
13481334
if (data is None or len(data) == 0):
13491335
print("No data")
13501336
return
@@ -1353,8 +1339,8 @@ def PrintValidatorList(ton, args):
13531339
print(text)
13541340
else:
13551341
table = list()
1356-
table += [["ADNL", "Pubkey", "Wallet", "Efficiency", "Online"]]
1357-
for item in data:
1342+
table += [["id", "ADNL", "Pubkey", "Wallet", "Efficiency", "Online"]]
1343+
for i, item in enumerate(data):
13581344
adnl = item.get("adnlAddr")
13591345
pubkey = item.get("pubkey")
13601346
walletAddr = item.get("walletAddr")
@@ -1372,7 +1358,7 @@ def PrintValidatorList(ton, args):
13721358
online = bcolors.green_text("true")
13731359
if online == False:
13741360
online = bcolors.red_text("false")
1375-
table += [[adnl, pubkey, walletAddr, efficiency, online]]
1361+
table += [[str(i), adnl, pubkey, walletAddr, efficiency, online]]
13761362
print_table(table)
13771363
#end define
13781364

mytonctrl/resources/translate.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@
219219
"ru": "Запустить установщик модулей TON",
220220
"zh_TW": "執行 TON 模組的安裝程序"
221221
},
222+
"check_ef_cmd": {
223+
"en": "Check the efficiency of the validator",
224+
"ru": "Проверить эффективность валидатора",
225+
"zh_TW": "檢查驗證者的效率"
226+
},
222227
"ton_status_head": {
223228
"en": "{cyan}===[ TON network status ]==={endc}",
224229
"ru": "{cyan}===[ Статус сети TON ]==={endc}",

mytonctrl/utils.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import subprocess
22
import time
33

4+
from mypylib.mypylib import bcolors
5+
46

57
def timestamp2utcdatetime(timestamp, format="%d.%m.%Y %H:%M:%S"):
68
datetime = time.gmtime(timestamp)
@@ -28,4 +30,20 @@ def fix_git_config(git_path: str):
2830
subprocess.run(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=3)
2931
else:
3032
raise Exception(f'Failed to check git status: {err}')
31-
#end define
33+
# end define
34+
35+
def GetColorInt(data, border, logic, ending=None):
36+
if data is None:
37+
result = "n/a"
38+
elif logic == "more":
39+
if data >= border:
40+
result = bcolors.green_text(data, ending)
41+
else:
42+
result = bcolors.red_text(data, ending)
43+
elif logic == "less":
44+
if data <= border:
45+
result = bcolors.green_text(data, ending)
46+
else:
47+
result = bcolors.red_text(data, ending)
48+
return result
49+
# end define

0 commit comments

Comments
 (0)