Skip to content

Commit b75f990

Browse files
committed
check if shard is descendant of already monitored shards when adding collator
1 parent 64c16fc commit b75f990

File tree

3 files changed

+97
-6
lines changed

3 files changed

+97
-6
lines changed

modules/collator.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from modules.module import MtcModule
22
from mypylib import color_print, print_table
3-
from mytoncore import b642hex, signed_int_to_hex64
3+
from mytoncore import b642hex, signed_int_to_hex64, shard_prefix_len, hex_shard_to_int, shard_prefix, shard_is_ancestor
44
from mytonctrl.utils import pop_arg_from_args
55

66

@@ -15,6 +15,32 @@ def add_collator_to_vc(self, adnl_addr: str, shard: str):
1515
result = self.ton.validatorConsole.Run(f"add-collator {adnl_addr} {shard}")
1616
return result
1717

18+
@staticmethod
19+
def _check_input_shards(node_shards: list, shards_need_to_add: list, monitor_min_split: int):
20+
true_monitoring_shards = []
21+
for sh in node_shards:
22+
shard_id = hex_shard_to_int(sh)
23+
if shard_id['workchain'] == -1:
24+
continue
25+
shard = shard_id['shard']
26+
if shard_prefix_len(shard) > monitor_min_split:
27+
shard_id['shard'] = shard_prefix(shard, monitor_min_split)
28+
true_monitoring_shards.append(shard_id)
29+
for sh in shards_need_to_add:
30+
shard_id = hex_shard_to_int(sh)
31+
found = False
32+
for true_shard in true_monitoring_shards:
33+
if shard_id['workchain'] == true_shard['workchain'] and \
34+
shard_is_ancestor(true_shard['shard'], shard_id['shard']):
35+
found = True
36+
break
37+
if not found:
38+
raise Exception(
39+
f'This node already has shards to monitor, '
40+
f'but shard {shard_id} is not monitored by the node: {true_monitoring_shards} It\'s highly not recommended to add new shards for node to monitor. '
41+
f'If you are sure you want to add new collator use option `--force`.'
42+
)
43+
1844
def setup_collator(self, args: list):
1945
from mytoninstaller.mytoninstaller import set_node_argument
2046
from mytoninstaller.node_args import get_node_args
@@ -29,10 +55,12 @@ def setup_collator(self, args: list):
2955
node_args = get_node_args()
3056
if '--add-shard' not in node_args:
3157
node_args['--add-shard'] = []
32-
shards_need_to_add = [shard for shard in shards if shard not in node_args['--add-shard']]
33-
if '-M' in node_args and shards_need_to_add and not force:
34-
raise Exception(f'This node already has shards to monitor. It\'s highly not recommended to add new shards for node to monitor. If you are sure you want to add new collator use option `--force`.')
3558

59+
node_shards = node_args['--add-shard']
60+
shards_need_to_add = [shard for shard in shards if shard not in node_shards]
61+
if not force and shards_need_to_add and '-M' in node_args:
62+
monitor_min_split = self.ton.get_basechain_config()['monitor_min_split']
63+
self._check_input_shards(node_shards, shards_need_to_add, monitor_min_split)
3664
if adnl_addr is None:
3765
adnl_addr = self.ton.CreateNewKey()
3866
self.ton.AddAdnlAddrToValidator(adnl_addr)

mytoncore/mytoncore.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,11 +636,14 @@ def GetMinStake(self):
636636

637637
def GetRootWorkchainEnabledTime(self):
638638
self.local.add_log("start GetRootWorkchainEnabledTime function", "debug")
639-
config12 = self.GetConfig(12)
640-
enabledTime = config12["workchains"]["root"]["node"]["value"]["enabled_since"]
639+
enabledTime = self.get_basechain_config()["enabled_since"]
641640
return enabledTime
642641
#end define
643642

643+
def get_basechain_config(self):
644+
config12 = self.GetConfig(12)
645+
return config12["workchains"]["root"]["node"]["value"]
646+
644647
def GetTotalValidators(self):
645648
self.local.add_log("start GetTotalValidators function", "debug")
646649
config34 = self.GetConfig34()

mytoncore/utils.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,63 @@ def signed_int_to_hex64(value):
117117
if value < 0:
118118
value = (1 << 64) + value
119119
return f"{value:016X}"
120+
121+
122+
_MASK64 = (1 << 64) - 1
123+
124+
125+
def _to_unsigned64(v: int) -> int:
126+
return v & _MASK64
127+
128+
129+
def _lower_bit64(u: int) -> int:
130+
if u == 0:
131+
return 0
132+
return u & ((-u) & _MASK64)
133+
134+
135+
def _bits_negate64(u: int) -> int:
136+
return ~u + 1
137+
138+
139+
def shard_prefix_len(shard_id: int):
140+
def _count_trailing_zeroes64(value: int) -> int:
141+
u = value & _MASK64
142+
if u == 0:
143+
return 64
144+
return ((u & -u).bit_length()) - 1
145+
return 63 - _count_trailing_zeroes64(_to_unsigned64(shard_id))
146+
147+
148+
def shard_prefix(shard_id: int, length_: int):
149+
150+
def _to_signed64(v: int) -> int:
151+
return v - (1 << 64) if v >= (1 << 63) else v
152+
153+
if not (0 <= length_ <= 63):
154+
raise ValueError("length must be between 0 and 63 inclusive")
155+
u = _to_unsigned64(shard_id)
156+
x = _lower_bit64(u)
157+
y = 1 << (63 - length_)
158+
if y < x:
159+
raise ValueError("requested prefix length is longer (more specific) than current shard id")
160+
mask_non_lower = (~(y - 1)) & _MASK64 # equals -y mod 2^64; clears bits below y
161+
res_u = (u & mask_non_lower) | y
162+
return _to_signed64(res_u)
163+
164+
165+
def shard_contains(parent: int, child: int) -> bool:
166+
parent = _to_unsigned64(parent)
167+
child = _to_unsigned64(child)
168+
x = _lower_bit64(parent)
169+
mask = (_bits_negate64(x) << 1) & _MASK64
170+
return not ((parent ^ child) & mask)
171+
172+
173+
def shard_is_ancestor(parent: int, child: int) -> bool:
174+
up = _to_unsigned64(parent)
175+
uc = _to_unsigned64(child)
176+
x = _lower_bit64(up)
177+
y = _lower_bit64(uc)
178+
mask = (_bits_negate64(x) << 1) & _MASK64
179+
return x >= y and not ((up ^ uc) & mask)

0 commit comments

Comments
 (0)