casper-devnet 0.9.1

Launcher for local Casper Network development networks.
Documentation
#!/usr/bin/env python3
import json
import pathlib
import subprocess
import sys
import typing
import urllib.error
import urllib.request


def main() -> int:
    if len(sys.argv) != 3:
        print(
            "usage: post-stage-protocol <network_name> <protocol_version>",
            file=sys.stderr,
        )
        return 2

    network_name, protocol_version = sys.argv[1:]
    print(
        "sample post-stage-protocol hook: "
        f"network={network_name} protocol_version={protocol_version}"
    )
    save_status_snapshot(network_name, pathlib.Path.cwd() / "info_get_status.json")
    return 0


def save_status_snapshot(network_name: str, output_path: pathlib.Path) -> None:
    rpc_url = optional_command_output(
        ["casper-devnet", "network", network_name, "port", "--rpc"]
    )
    if not rpc_url:
        return

    payload = json.dumps(
        {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "info_get_status",
            "params": [],
        }
    ).encode("utf-8")
    request = urllib.request.Request(
        rpc_url,
        data=payload,
        headers={"content-type": "application/json"},
        method="POST",
    )

    try:
        with urllib.request.urlopen(request, timeout=5) as response:
            output_path.write_bytes(response.read())
    except (OSError, urllib.error.URLError):
        remove_if_exists(output_path)


def optional_command_output(argv: typing.List[str]) -> typing.Optional[str]:
    result = subprocess.run(argv, capture_output=True, text=True)
    if result.returncode != 0:
        return None
    output = result.stdout.strip()
    return output or None


def remove_if_exists(path: pathlib.Path) -> None:
    try:
        path.unlink()
    except FileNotFoundError:
        pass


if __name__ == "__main__":
    raise SystemExit(main())