Skip to content

Instantly share code, notes, and snippets.

@lucadonnoh
Last active May 23, 2024 13:26
Show Gist options
  • Save lucadonnoh/5911061e340086213fc837496b0ff74d to your computer and use it in GitHub Desktop.
Save lucadonnoh/5911061e340086213fc837496b0ff74d to your computer and use it in GitHub Desktop.
Calculate the exit window given chain params such as timelocks and other delays.
from datetime import timedelta, datetime
CHALLENGE_PERIOD = timedelta(days=7)
FORCED_TRANSACTION_DELAY = timedelta(days=1)
L2_TIMELOCK_DELAY = timedelta(days=3)
L1_TIMELOCK_DELAY = timedelta(days=3)
SELF_PROPOSE_DELAY = timedelta(days=7)
"""
ASSUMPTIONS:
- Operators want to push a malicious upgrade
- Whitelisted sequencers/proposers are perfectly coordinated
- Sequencers can censor withdrawals sent directly on L2
- The user decides to exit after the upgrade is proposed
"""
random_delta = timedelta(minutes=1)
# random_delta = timedelta(seconds=0) # comment if you want to see random deltas
USER_ESCAPE_START = timedelta(days=2) + random_delta
events = []
start_time = datetime.now()
print("")
exit_window = timedelta(
seconds=max(L1_TIMELOCK_DELAY.total_seconds() + L2_TIMELOCK_DELAY.total_seconds() - FORCED_TRANSACTION_DELAY.total_seconds() - SELF_PROPOSE_DELAY.total_seconds(), max(L2_TIMELOCK_DELAY.total_seconds() - FORCED_TRANSACTION_DELAY.total_seconds(), 0)))
print("Exit window: {}".format(exit_window))
def elapsed(time):
return time - start_time
upgrade_initiation_time = start_time
events.append(["Upgrade reaches L2 Timelock",
elapsed(upgrade_initiation_time), "red"])
# the withdrawer pushes the withdrawal transaction to L2 via L1 using the DelayedInbox
withdrawal_time = upgrade_initiation_time + USER_ESCAPE_START
events.append(["Withdrawal pushed to L2 via L1 (DelayedInbox)",
elapsed(withdrawal_time), "green"])
# after the FORCED_TRANSACTION_DELAY, the transaction can be moved to the Inbox
sequenced_time = withdrawal_time + FORCED_TRANSACTION_DELAY
events.append(["Withdrawal sequenced (Inbox)",
elapsed(sequenced_time), "green"])
# proposers now stop posting state roots
# after the L2_TIMELOCK_DELAY, the upgrade can be sent to L1, but a state root must be posted
# this state root inevitably contains the withdrawal transaction
upgrade_challenge_period_start = upgrade_initiation_time + L2_TIMELOCK_DELAY
events.append(["Upgrade sent to L1", elapsed(
upgrade_challenge_period_start), "red"])
containsWithdrawal = ""
if (sequenced_time <= upgrade_challenge_period_start):
events.append(
["The state root contains both the withdrawal and the upgrade", elapsed(upgrade_challenge_period_start), "green"])
containsWithdrawal = " (and withdrawal)"
else:
events.append(
["The state root contains only the upgrade, operators stop producing roots", elapsed(upgrade_challenge_period_start), "red"])
self_proposed_root_proposal_time = sequenced_time + SELF_PROPOSE_DELAY
events.append(["Withdrawal posted in a self-proposed state root",
elapsed(self_proposed_root_proposal_time), "green"])
self_proposed_root_finalization_time = self_proposed_root_proposal_time + CHALLENGE_PERIOD
events.append(["Self-proposed state root finalized",
elapsed(self_proposed_root_finalization_time), "green"])
# after the CHALLENGE_PERIOD, the upgrade is accepted on L2, but also the withdrawal transaction
upgrade_challenge_period_end = upgrade_challenge_period_start + CHALLENGE_PERIOD
events.append(["Upgrade" + containsWithdrawal + " reaches L1 Timelock",
elapsed(upgrade_challenge_period_end), ("green" if containsWithdrawal else "red")])
# the withdrawal has been executed
upgrade_execution_time = upgrade_challenge_period_end + L1_TIMELOCK_DELAY
events.append(["Upgrade executed \n ####### NOTHING MATTERS FROM HERE #######",
elapsed(upgrade_execution_time), "red"])
# order events by time
events.sort(key=lambda x: x[1])
def print_colored(text, color):
if color == "red":
print("\033[91m {}\033[00m".format(text))
elif color == "green":
print("\033[92m {}\033[00m".format(text))
elif color == "blue":
print("\033[94m {}\033[00m".format(text))
else:
print(text)
label_width = max(len("CHALLENGE_PERIOD"),
len("FORCED_TRANSACTION_DELAY"),
len("L2_TIMELOCK_DELAY"),
len("L1_TIMELOCK_DELAY"),
len("SELF_PROPOSE_DELAY"),
len("USER_ESCAPE_DELAY")) + 1
print("")
print(f"{'CHALLENGE_PERIOD:':<{label_width}} {CHALLENGE_PERIOD}")
print(f"{'FORCED_TRANSACTION_DELAY:':<{label_width}} {FORCED_TRANSACTION_DELAY}")
print(f"{'L2_TIMELOCK_DELAY:':<{label_width}} {L2_TIMELOCK_DELAY}")
print(f"{'L1_TIMELOCK_DELAY:':<{label_width}} {L1_TIMELOCK_DELAY}")
print(f"{'SELF_PROPOSE_DELAY:':<{label_width}} {SELF_PROPOSE_DELAY}")
print(f"{'USER_ESCAPE_START:':<{label_width}} {USER_ESCAPE_START}")
print("")
for event in events:
print_colored("{} - {}".format(event[1], event[0]), event[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment