diff --git a/debug_scripts/estimate_epoch_start_time.py b/debug_scripts/estimate_epoch_start_time.py index b298f6a7607..b5bb568a6cd 100644 --- a/debug_scripts/estimate_epoch_start_time.py +++ b/debug_scripts/estimate_epoch_start_time.py @@ -119,6 +119,54 @@ def find_epoch_for_timestamp(future_epochs, voting_timestamp): return len(future_epochs) +def find_best_voting_hour(voting_date_str, future_epochs): + # Working hours during which there are available NEAR engineers + WORKING_HOURS_START = 8 # 8:00 UTC + WORKING_HOURS_END = 22 # 22:00 UTC + + valid_hours = [] + + for hour in range(24): + # Construct datetime for each hour of the voting date + voting_datetime = datetime.strptime( + f"{voting_date_str} {hour:02d}:00:00", '%Y-%m-%d %H:%M:%S') + voting_datetime = pytz.utc.localize(voting_datetime) + voting_timestamp = voting_datetime.timestamp() + + # Find the epoch T in which the voting date falls + epoch_T = find_epoch_for_timestamp(future_epochs, voting_timestamp) + if epoch_T <= 0: + continue # Voting date is before the first predicted epoch + + # Calculate when the protocol upgrade will happen (start of epoch T+2) + protocol_upgrade_epoch_number = epoch_T + 2 + if protocol_upgrade_epoch_number > len(future_epochs): + print( + "Not enough future epochs predicted to determine all the protocol upgrade times." + ) + break + + protocol_upgrade_timestamp = future_epochs[protocol_upgrade_epoch_number + - 1] + protocol_upgrade_datetime = datetime.fromtimestamp( + protocol_upgrade_timestamp) + upgrade_hour_utc = protocol_upgrade_datetime.hour + + if WORKING_HOURS_START <= upgrade_hour_utc < WORKING_HOURS_END: + valid_hours.append((hour, protocol_upgrade_epoch_number)) + + if valid_hours: + print( + f"\nVoting hours on {voting_date_str} UTC that result in upgrade during working hours (UTC {WORKING_HOURS_START}:00-{WORKING_HOURS_END}:00):" + ) + for (hour, epoch) in valid_hours: + print(f"- {hour:02d}:00, Upgrade Epoch: {epoch}") + else: + print( + "\nNo voting hours on the given date result in an upgrade during working hours." + ) + + def valid_voting_datetime(s): try: dt = datetime.strptime(s, '%Y-%m-%d %H:%M:%S') @@ -178,6 +226,8 @@ def main(args): if args.voting_date: find_protocol_upgrade_time(args.voting_date, future_epochs, args.timezone) + elif args.voting_date_day: + find_best_voting_hour(args.voting_date_day, future_epochs) # Custom action to set the URL based on chain_id @@ -222,9 +272,17 @@ def __call__(self, parser, namespace, values, option_string=None): type=valid_timezone, default="UTC", help="Time zone to display times in (e.g., 'America/New_York').") - parser.add_argument("--voting_date", - type=valid_voting_datetime, - help="Voting date in 'YYYY-MM-DD HH:MM:SS' format.") + # Voting date arguments + voting_group = parser.add_mutually_exclusive_group() + voting_group.add_argument( + "--voting_date", + type=valid_voting_datetime, + help="Voting date in 'YYYY-MM-DD HH:MM:SS' format.") + voting_group.add_argument( + "--voting_date_day", + help= + "Voting date (day) in 'YYYY-MM-DD' format to find voting hours resulting in upgrade during working hours." + ) args = parser.parse_args() main(args)