diff --git a/scripts/finalize_handover.py b/scripts/finalize_handover.py index 620fe61e2..e407ce316 100644 --- a/scripts/finalize_handover.py +++ b/scripts/finalize_handover.py @@ -11,7 +11,7 @@ from deployment.utils import check_plugins -def validate_handover_data(coordinator, ritual_id, departing_provider): +def validate_handover_data(coordinator, ritual_id, departing_provider, incoming_provider=None): """Validate the handover data for the ritual.""" handover_key = coordinator.getHandoverKey(ritual_id, departing_provider) handover = coordinator.handovers(handover_key) @@ -19,6 +19,9 @@ def validate_handover_data(coordinator, ritual_id, departing_provider): HandoverTranscript.from_bytes(handover.transcript) is not None ), "Handover transcript should be valid" + if incoming_provider: + assert handover.incomingProvider.lower() == incoming_provider.lower(), "Incoming provider should match" + ritual = coordinator.rituals(ritual_id) existing_aggregated_transcript = ritual.aggregatedTranscript @@ -75,6 +78,13 @@ def validate_handover_data(coordinator, ritual_id, departing_provider): required=True, type=ChecksumAddress(), ) +@click.option( + "--incoming-provider", + "-ip", + help="The ethereum address of the incoming staking provider.", + required=True, + type=ChecksumAddress(), +) @click.option( "--auto", help="Automatically sign transactions.", @@ -86,6 +96,7 @@ def cli( network, ritual_id, departing_provider, + incoming_provider, auto, ): """Finalize the handover.""" diff --git a/scripts/request_handover.py b/scripts/request_handover.py index f2786b939..7885b238b 100644 --- a/scripts/request_handover.py +++ b/scripts/request_handover.py @@ -9,6 +9,44 @@ from deployment.types import ChecksumAddress from deployment.utils import check_plugins +STATUS_ENDPOINT = "https://mainnet.nucypher.network:9151/status/?json=true" + +def check_incoming_provider(incoming_provider: str) -> bool: + """Checks if the incoming provider is active and has a valid status on the status endpoint.""" + import requests + + response = requests.get(STATUS_ENDPOINT, verify=False) + response.raise_for_status() + data = response.json() + + for node_data in data["known_nodes"]: + if node_data["staker_address"].lower() == incoming_provider.lower(): + url = node_data["rest_url"] + # let's ping the node's REST endpoint to check if it's active + try: + node_status_page = f"https://{url}/status/?json=true" + node_response = requests.get(node_status_page, verify=False) + node_response.raise_for_status() + node_status_data = node_response.json() + + version = node_status_data["version"] + click.echo(f"Incoming provider {incoming_provider} is active with version {version}.") + if version.startswith("7.7") or version.startswith("7.6.1"): + return True + else: + click.echo( + f"Incoming provider {incoming_provider} is running an incompatible version: {version}." + ) + return False + + except requests.RequestException as e: + click.echo(f"Error occurred while checking node status: {e}") + return False + + else: + click.echo(f"Incoming provider {incoming_provider} is not active.") + return False + @click.command(cls=ConnectedProviderCommand, name="request-handover") @account_option() @@ -55,6 +93,11 @@ def cli( check_plugins() click.echo(f"Connected to {network.name} network.") + # Check if incoming provider is active and has a valid status + if not check_incoming_provider(incoming_provider): + click.echo("Incoming provider is not active or has an invalid status. Aborting.") + return + # Get the contracts from the registry coordinator_contract = registry.get_contract(domain=domain, contract_name="Coordinator")