diff options
| author | Monzero Build System <builds@monzero.org> | 2026-08-15 21:14:26 +0100 |
|---|---|---|
| committer | Monzero Build System <builds@monzero.org> | 2026-08-15 21:14:26 +0100 |
| commit | 28f1919249465d3230f45ed21686c5a836d56df0 (patch) | |
| tree | 948fe5e7052c45c366c24a82b485ae9d1d38e39b /utils | |
| parent | 4f92268d7c16741cfb41e5bbe2aa46cc260a9ea5 (diff) | |
| download | monzero-core-28f1919249465d3230f45ed21686c5a836d56df0.tar.gz monzero-core-28f1919249465d3230f45ed21686c5a836d56df0.tar.xz monzero-core-28f1919249465d3230f45ed21686c5a836d56df0.zip | |
Establish Monzero Phase 0 and inactive assets baselinemonzero-phase0-assets-prototype-20260815
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/configure-miner-stats.php | 30 | ||||
| -rwxr-xr-x | utils/monzero-miner-reporter.py | 93 | ||||
| -rwxr-xr-x | utils/release/package-linux.sh | 84 | ||||
| -rwxr-xr-x | utils/release/verify-package.sh | 53 |
4 files changed, 260 insertions, 0 deletions
diff --git a/utils/configure-miner-stats.php b/utils/configure-miner-stats.php new file mode 100644 index 000000000..7b2f72d34 --- /dev/null +++ b/utils/configure-miner-stats.php @@ -0,0 +1,30 @@ +<?php +declare(strict_types=1); + +if (PHP_SAPI !== 'cli' || $argc !== 3) { + fwrite(STDERR, "Usage: php configure-miner-stats.php CONFIG_PATH DATA_PATH\n"); + exit(1); +} + +$configPath = $argv[1]; +$dataPath = $argv[2]; +if (file_exists($configPath)) { + fwrite(STDERR, "Refusing to overwrite existing configuration: {$configPath}\n"); + exit(1); +} + +$serverSecret = bin2hex(random_bytes(32)); +$ingestToken = bin2hex(random_bytes(32)); +$config = "<?php\nreturn " . var_export([ + 'MONZERO_STATS_SECRET' => $serverSecret, + 'MONZERO_STATS_INGEST_TOKEN' => $ingestToken, + 'MONZERO_STATS_FILE' => $dataPath, +], true) . ";\n"; + +if (file_put_contents($configPath, $config, LOCK_EX) === false) { + fwrite(STDERR, "Unable to create configuration.\n"); + exit(1); +} +chmod($configPath, 0600); + +fwrite(STDOUT, "Configuration created. Team ingest token (save privately):\n{$ingestToken}\n"); diff --git a/utils/monzero-miner-reporter.py b/utils/monzero-miner-reporter.py new file mode 100755 index 000000000..cbbc3029a --- /dev/null +++ b/utils/monzero-miner-reporter.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +"""Opt-in anonymous mining telemetry reporter for monzero.org.""" + +from __future__ import annotations + +import argparse +import json +import os +import re +import stat +import time +import urllib.error +import urllib.request +import uuid +from pathlib import Path + + +FOUND_BLOCK = re.compile(r"Found block [0-9a-f]+ at height ", re.IGNORECASE) + + +def json_request(url: str, body: dict | None = None, token: str = "") -> dict: + data = None if body is None else json.dumps(body).encode("utf-8") + headers = {"Accept": "application/json"} + if data is not None: + headers["Content-Type"] = "application/json" + if token: + headers["Authorization"] = f"Bearer {token}" + request = urllib.request.Request(url, data=data, headers=headers) + with urllib.request.urlopen(request, timeout=8) as response: + return json.load(response) + + +def installation_id(path: Path) -> str: + if path.exists(): + return path.read_text(encoding="ascii").strip() + path.parent.mkdir(parents=True, exist_ok=True) + value = str(uuid.uuid4()) + path.write_text(value + "\n", encoding="ascii") + path.chmod(stat.S_IRUSR | stat.S_IWUSR) + return value + + +def blocks_found(log_path: Path) -> int: + try: + with log_path.open("r", encoding="utf-8", errors="ignore") as log: + return sum(1 for line in log if FOUND_BLOCK.search(line)) + except FileNotFoundError: + return 0 + + +def report(args: argparse.Namespace) -> None: + status = json_request(args.rpc.rstrip("/") + "/mining_status", {}) + payload = { + "installation_id": installation_id(args.id_file), + "hashrate": int(status.get("speed", 0)) if status.get("active") else 0, + "blocks_found": blocks_found(args.log), + } + result = json_request(args.endpoint, payload, args.token) + if result.get("status") != "OK": + raise RuntimeError(f"telemetry rejected: {result}") + print( + f"reported {payload['hashrate']} H/s and " + f"{payload['blocks_found']} block(s); no wallet or hardware ID sent" + ) + + +def main() -> None: + default_data = Path.home() / ".monzero" + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--endpoint", default="https://monzero.org/api/miner-stats/") + parser.add_argument("--rpc", default="http://127.0.0.1:6175") + parser.add_argument("--token", default=os.environ.get("MONZERO_STATS_TOKEN", "")) + parser.add_argument("--id-file", type=Path, default=default_data / "telemetry-id") + parser.add_argument("--log", type=Path, default=default_data / "monzero.log") + parser.add_argument("--interval", type=int, default=0, help="repeat every N seconds") + args = parser.parse_args() + if not args.token: + parser.error("set MONZERO_STATS_TOKEN or pass --token") + if args.interval and args.interval < 30: + parser.error("--interval must be at least 30 seconds") + + while True: + try: + report(args) + except (OSError, ValueError, urllib.error.URLError, RuntimeError) as error: + print(f"report failed: {error}") + if not args.interval: + break + time.sleep(args.interval) + + +if __name__ == "__main__": + main() diff --git a/utils/release/package-linux.sh b/utils/release/package-linux.sh new file mode 100755 index 000000000..bcc659e57 --- /dev/null +++ b/utils/release/package-linux.sh @@ -0,0 +1,84 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + echo "Usage: $0 <build-bin-dir> <output-dir> <version>" >&2 + echo "Set ALLOW_DIRTY=1 only for an explicitly marked development artifact." >&2 + exit 2 +} + +[[ $# -eq 3 ]] || usage + +source_root=$(git rev-parse --show-toplevel) +build_bin=$(realpath "$1") +output_dir=$(realpath -m "$2") +version=$3 + +[[ $version =~ ^[0-9A-Za-z][0-9A-Za-z._-]*$ ]] || { echo "Invalid version label" >&2; exit 2; } +[[ -x "$build_bin/monzerod" ]] || { echo "Missing executable: $build_bin/monzerod" >&2; exit 2; } +[[ -x "$build_bin/monzero-wallet-cli" ]] || { echo "Missing executable: $build_bin/monzero-wallet-cli" >&2; exit 2; } + +source_commit=$(git -C "$source_root" rev-parse HEAD) +source_epoch=${SOURCE_DATE_EPOCH:-$(git -C "$source_root" show -s --format=%ct "$source_commit")} +[[ $source_epoch =~ ^[0-9]+$ ]] || { echo "SOURCE_DATE_EPOCH must be an integer" >&2; exit 2; } + +dirty=false +if [[ -n $(git -C "$source_root" status --porcelain --untracked-files=normal) ]]; then + dirty=true + [[ ${ALLOW_DIRTY:-0} == 1 ]] || { + echo "Refusing to package a dirty source tree. Commit the reviewed baseline first." >&2 + exit 1 + } + version="${version}-development-dirty" +fi + +package_name="monzero-${version}-linux-x86_64" +mkdir -p "$output_dir" +work_dir=$(mktemp -d "${TMPDIR:-/tmp}/monzero-package.XXXXXX") +trap 'rm -rf -- "$work_dir"' EXIT +package_dir="$work_dir/$package_name" +mkdir -p "$package_dir" + +install -m 0755 "$build_bin/monzerod" "$package_dir/monzerod" +install -m 0755 "$build_bin/monzero-wallet-cli" "$package_dir/monzero-wallet-cli" +for optional in monzero-wallet-rpc monzero-gen-ssl-cert; do + [[ -x "$build_bin/$optional" ]] && install -m 0755 "$build_bin/$optional" "$package_dir/$optional" +done + +install -m 0755 "$source_root/start-monzerod.sh" "$package_dir/start-monzerod.sh" +install -m 0755 "$source_root/start-monzero-wallet-cli.sh" "$package_dir/start-monzero-wallet-cli.sh" +install -m 0755 "$source_root/start-monzero-miner.sh" "$package_dir/start-monzero-miner.sh" +install -m 0755 "$source_root/stop-monzero-miner.sh" "$package_dir/stop-monzero-miner.sh" +install -m 0644 "$source_root/LICENSE" "$package_dir/LICENSE" +install -m 0644 "$source_root/MONZERO_CHAIN_SPEC.md" "$package_dir/MONZERO_CHAIN_SPEC.md" +install -m 0644 "$source_root/docs/RELEASE_CHECKLIST.md" "$package_dir/RELEASE_CHECKLIST.md" + +{ + echo "package=$package_name" + echo "source_commit=$source_commit" + echo "source_date_epoch=$source_epoch" + echo "source_tree_dirty=$dirty" + echo "binary_build_reproducibility=unverified" + echo "assets_consensus_enabled=false" + echo "native_ticker=XMZ" +} > "$package_dir/BUILD-MANIFEST.txt" + +( + cd "$package_dir" + find . -maxdepth 1 -type f ! -name SHA256SUMS -printf '%P\n' \ + | LC_ALL=C sort \ + | xargs -r sha256sum > SHA256SUMS + sha256sum -c SHA256SUMS +) + +archive="$output_dir/$package_name.tar.gz" +tar --sort=name \ + --mtime="@$source_epoch" \ + --owner=0 --group=0 --numeric-owner \ + --pax-option=delete=atime,delete=ctime \ + -C "$work_dir" -cf - "$package_name" \ + | gzip -n -9 > "$archive" +sha256sum "$archive" > "$archive.sha256" + +echo "$archive" +echo "$archive.sha256" diff --git a/utils/release/verify-package.sh b/utils/release/verify-package.sh new file mode 100755 index 000000000..22ccab4c8 --- /dev/null +++ b/utils/release/verify-package.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +[[ $# -eq 1 ]] || { echo "Usage: $0 <monzero-linux.tar.gz>" >&2; exit 2; } +archive=$(realpath "$1") +[[ -f "$archive" ]] || { echo "Archive not found: $archive" >&2; exit 2; } + +work_dir=$(mktemp -d "${TMPDIR:-/tmp}/monzero-verify.XXXXXX") +trap 'rm -rf -- "$work_dir"' EXIT +tar -xzf "$archive" -C "$work_dir" + +mapfile -t roots < <(find "$work_dir" -mindepth 1 -maxdepth 1 -type d) +[[ ${#roots[@]} -eq 1 ]] || { echo "Archive must contain exactly one root directory" >&2; exit 1; } +root=${roots[0]} + +[[ -x "$root/monzerod" && -x "$root/monzero-wallet-cli" ]] || { + echo "Required Monzero executables are missing" >&2 + exit 1 +} +[[ -f "$root/BUILD-MANIFEST.txt" && -f "$root/SHA256SUMS" ]] || { + echo "Build or checksum manifest is missing" >&2 + exit 1 +} + +if find "$root" -type l -print -quit | grep -q .; then + echo "Package contains symbolic links" >&2 + exit 1 +fi + +( + cd "$root" + sha256sum -c SHA256SUMS +) + +binary_report=$(file "$root/monzerod" "$root/monzero-wallet-cli") +echo "$binary_report" +if [[ ${RELEASE_STRICT:-0} == 1 ]]; then + if grep -Eq 'dynamically linked|not stripped|with debug_info' <<< "$binary_report"; then + echo "Strict release verification rejects dynamic, unstripped, or debug binaries" >&2 + exit 1 + fi + grep -qx 'source_tree_dirty=false' "$root/BUILD-MANIFEST.txt" || { + echo "Strict release verification rejects a dirty source manifest" >&2 + exit 1 + } + grep -qx 'binary_build_reproducibility=verified' "$root/BUILD-MANIFEST.txt" || { + echo "Strict release verification requires independently verified binary reproducibility" >&2 + exit 1 + } +fi +"$root/monzerod" --version +"$root/monzero-wallet-cli" --version +echo "Package verification passed: $archive" |
