diff --git a/.envrc b/.envrc index 3851773c..71300b1d 100644 --- a/.envrc +++ b/.envrc @@ -1,5 +1,2 @@ -if ! has nix_direnv_version || ! nix_direnv_version 2.2.0; then - source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/2.2.0/direnvrc" "sha256-5EwyKnkJNQeXrRkYbwwRBcXbibosCJqyIUuz9Xq+LRc=" -fi -nix_direnv_watch_file ./flake-shell.nix +watch_file ./flake-shell.nix use flake diff --git a/flake.nix b/flake.nix index 748a6cac..5277b6c0 100644 --- a/flake.nix +++ b/flake.nix @@ -76,7 +76,7 @@ ./modules ./pkgs ]; - systems = import systems; + systems = (import systems) ++ ["i686-linux"]; perSystem = { config, pkgs, @@ -131,6 +131,7 @@ flakeCheck = true; programs = { alejandra.enable = true; + black.enable = true; deadnix.enable = true; deno.enable = true; mdformat.enable = true; diff --git a/maintainers/scripts/update/update.nix b/maintainers/scripts/update/update.nix new file mode 100644 index 00000000..29dfa907 --- /dev/null +++ b/maintainers/scripts/update/update.nix @@ -0,0 +1,65 @@ +{ + flakePath ? ./., + system ? "x86_64-linux", + input ? "nixpkgs", + max-workers ? null, + keep-going ? null, + commit ? null, + no-confirm ? null, +}: let + flake = builtins.getFlake (builtins.toString flakePath); + + pkgs = flake.inputs.${input}.legacyPackages.${system}; + inherit (pkgs) lib; + + filterPkgsWithUpdateScript = pkgs: + lib.filterAttrs ( + _name: pkg: + lib.isDerivation pkg && lib.hasAttrByPath ["passthru" "updateScript"] pkg + ) + pkgs; + + flakePkgs = flake.packages.${system}; + + filteredPackages = filterPkgsWithUpdateScript flakePkgs; + + packageData = name: package: { + inherit name; + pname = lib.getName package; + oldVersion = lib.getVersion package; + inherit (package.passthru) updateScript; + attrPath = name; + }; + + packagesJson = pkgs.writeText "packages.json" (builtins.toJSON (lib.mapAttrsToList packageData filteredPackages)); + + optionalArgs = + lib.optional (max-workers != null) "--max-workers=${toString max-workers}" + ++ lib.optional (keep-going == "true") "--keep-going" + ++ lib.optional (no-confirm == "true") "--no-confirm" + ++ lib.optional (commit == "true") "--commit"; + + args = [packagesJson] ++ optionalArgs; + + python = pkgs.python311.withPackages (ps: + with ps; [ + click + ]); +in + pkgs.stdenv.mkDerivation { + name = "flake-packages-update-script"; + buildCommand = '' + echo "" + echo "----------------------------------------------------------------" + echo "" + echo "Not possible to update packages using \`nix-build\`" + echo "Please use \`nix-shell\` with this derivation." + echo "" + echo "----------------------------------------------------------------" + exit 1 + ''; + shellHook = '' + unset shellHook # Prevent contamination in nested shells. + exec ${python}/bin/python ${./update.py} ${builtins.concatStringsSep " " args} + ''; + } diff --git a/maintainers/scripts/update/update.py b/maintainers/scripts/update/update.py new file mode 100644 index 00000000..d7870046 --- /dev/null +++ b/maintainers/scripts/update/update.py @@ -0,0 +1,363 @@ +import asyncio +import contextlib +import json +import logging +import os +import re +import subprocess +import sys +import tempfile +from typing import Dict, Generator, List, Optional, Tuple, TypedDict + +import click + + +class CalledProcessError(Exception): + process: asyncio.subprocess.Process + + +class UpdateFailedException(Exception): + pass + + +class Package(TypedDict): + name: str + pname: str + oldVersion: str + attrPath: str + updateScript: List[str] + + +async def check_subprocess(*args, **kwargs): + """ + Emulate check argument of subprocess.run function. + """ + process = await asyncio.create_subprocess_exec(*args, **kwargs) + returncode = await process.wait() + + if returncode != 0: + error = CalledProcessError() + error.process = process + + raise error + + return process + + +async def run_update_script( + dir_root: str, + merge_lock: asyncio.Lock, + temp_dir: Optional[Tuple[str, str]], + package: Dict, + keep_going: bool, +): + worktree: Optional[str] = None + + update_script_command = package["updateScript"] + + if temp_dir is not None: + worktree, _branch = temp_dir + + # Ensure the worktree is clean before update. + await check_subprocess( + "git", "reset", "--hard", "--quiet", "HEAD", cwd=worktree + ) + + # Update scripts can use $(dirname $0) to get their location but we want to run + # their clones in the git worktree, not in the main nixpkgs repo. + update_script_command = map( + lambda arg: re.sub(r"^{0}".format(re.escape(dir_root)), worktree, arg), + update_script_command, + ) + + logging.info(f" - {package['name']}: UPDATING ...") + + try: + update_process = await check_subprocess( + "env", + f"UPDATE_NIX_NAME={package['name']}", + f"UPDATE_NIX_PNAME={package['pname']}", + f"UPDATE_NIX_OLD_VERSION={package['oldVersion']}", + f"UPDATE_NIX_ATTR_PATH={package['attrPath']}", + *update_script_command, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + cwd=worktree, + ) + update_info = await update_process.stdout.read() + + await merge_changes(merge_lock, package, update_info, temp_dir) + except KeyboardInterrupt: + logging.info("Cancelling…") + raise asyncio.exceptions.CancelledError() + except CalledProcessError as e: + logging.error(f" - {package['name']}: ERROR") + logging.info("") + logging.error( + f"--- SHOWING ERROR LOG FOR {package['name']} ----------------------" + ) + logging.error("") + stderr = await e.process.stderr.read() + logging.error(stderr.decode("utf-8")) + logging.error("") + logging.error( + f"--- SHOWING ERROR LOG FOR {package['name']} ----------------------" + ) + + if not keep_going: + raise UpdateFailedException( + f"The update script for {package['name']} failed with exit code {e.process.returncode}" + ) + + +@contextlib.contextmanager +def make_worktree() -> Generator[Tuple[str, str], None, None]: + with tempfile.TemporaryDirectory() as wt: + branch_name = f"update-{os.path.basename(wt)}" + target_directory = f"{wt}/nixpkgs" + + subprocess.run(["git", "worktree", "add", "-b", branch_name, target_directory]) + yield (target_directory, branch_name) + subprocess.run(["git", "worktree", "remove", "--force", target_directory]) + subprocess.run(["git", "branch", "-D", branch_name]) + + +async def commit_changes( + name: str, merge_lock: asyncio.Lock, worktree: str, branch: str, changes: List[Dict] +) -> None: + for change in changes: + # Git can only handle a single index operation at a time + async with merge_lock: + await check_subprocess("git", "add", *change["files"], cwd=worktree) + commit_message = "{attrPath}: {oldVersion} -> {newVersion}".format(**change) + if "commitMessage" in change: + commit_message = change["commitMessage"] + elif "commitBody" in change: + commit_message = commit_message + "\n\n" + change["commitBody"] + await check_subprocess( + "git", "commit", "--quiet", "-m", commit_message, cwd=worktree + ) + await check_subprocess("git", "cherry-pick", branch) + + +async def check_changes(package: Dict, worktree: str, update_info: str): + if "commit" in package.get("supportedFeatures", []): + changes = json.loads(update_info) + else: + changes = [{}] + + # Try to fill in missing attributes when there is just a single change. + if len(changes) == 1: + # Dynamic data from updater take precedence over static data from passthru.updateScript. + if "attrPath" not in changes[0]: + # update.nix is always passing attrPath + changes[0]["attrPath"] = package["attrPath"] + + if "oldVersion" not in changes[0]: + # update.nix is always passing oldVersion + changes[0]["oldVersion"] = package["oldVersion"] + + if "newVersion" not in changes[0]: + attr_path = changes[0]["attrPath"] + logging.info(f"Current worktree: {worktree}") + obtain_new_version_process = await check_subprocess( + "nix", + "eval", + f".#packages.x86_64-linux.{attr_path}.version", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + cwd=worktree, + ) + changes[0]["newVersion"] = json.loads( + (await obtain_new_version_process.stdout.read()).decode("utf-8") + ) + + if "files" not in changes[0]: + changed_files_process = await check_subprocess( + "git", + "diff", + "--name-only", + "HEAD", + stdout=asyncio.subprocess.PIPE, + cwd=worktree, + ) + changed_files = (await changed_files_process.stdout.read()).splitlines() + changes[0]["files"] = changed_files + + if len(changed_files) == 0: + return [] + + return changes + + +async def merge_changes( + merge_lock: asyncio.Lock, + package: Dict, + update_info: str, + temp_dir: Optional[Tuple[str, str]], +) -> None: + if temp_dir is not None: + worktree, branch = temp_dir + changes = await check_changes(package, worktree, update_info) + + if len(changes) > 0: + await commit_changes(package["name"], merge_lock, worktree, branch, changes) + else: + logging.info(f" - {package['name']}: DONE, no changes.") + else: + logging.info(f" - {package['name']}: DONE.") + + +async def updater( + dir_root: str, + temp_dir: Optional[Tuple[str, str]], + merge_lock: asyncio.Lock, + packages_to_update: asyncio.Queue[Optional[Dict]], + keep_going: bool, + commit: bool, +): + while True: + package = await packages_to_update.get() + if package is None: + # A sentinel received, we are done. + return + + if not ( + "commit" in package.get("supportedFeatures", []) or "attrPath" in package + ): + temp_dir = None + + await run_update_script(dir_root, merge_lock, temp_dir, package, keep_going) + + +async def start_updates( + max_workers: int, keep_going: bool, commit: bool, packages: List[Dict] +): + merge_lock = asyncio.Lock() + packages_to_update: asyncio.Queue[Optional[Dict]] = asyncio.Queue() + + with contextlib.ExitStack() as stack: + temp_dirs: List[Optional[Tuple[str, str]]] = [] + + # Do not create more workers than there are packages. + num_workers = min(max_workers, len(packages)) + + dir_root_process = await check_subprocess( + "git", "rev-parse", "--show-toplevel", stdout=asyncio.subprocess.PIPE + ) + dir_root = (await dir_root_process.stdout.read()).decode("utf-8").strip() + + # Set up temporary directories when using auto-commit. + for _ in range(num_workers): + temp_dir = stack.enter_context(make_worktree()) if commit else None + temp_dirs.append(temp_dir) + + # Fill up an update queue, + for package in packages: + await packages_to_update.put(package) + + # Add sentinels, one for each worker. + # A workers will terminate when it gets sentinel from the queue. + for _ in range(num_workers): + await packages_to_update.put(None) + + # Prepare updater workers for each temp_dir directory. + # At most `num_workers` instances of `run_update_script` will be running at one time. + updaters = asyncio.gather( + *[ + updater( + dir_root, + temp_dir, + merge_lock, + packages_to_update, + keep_going, + commit, + ) + for temp_dir in temp_dirs + ] + ) + + try: + # Start updater workers. + await updaters + except asyncio.exceptions.CancelledError: + # When one worker is cancelled, cancel the others too. + updaters.cancel() + except UpdateFailedException as e: + # When one worker fails, cancel the others, as this exception is only thrown when keep_going is false. + updaters.cancel() + logging.error(e) + sys.exit(1) + + +@click.command() +@click.option( + "--max-workers", + "-j", + default=4, + help="Number of updates to run concurrently", + type=int, +) +@click.option( + "--keep-going", "-k", is_flag=True, help="Do not stop after first failure" +) +@click.option("--commit", "-c", is_flag=True, help="Commit the changes") +@click.option( + "--no-confirm", + "-n", + is_flag=True, + help="Skip the confirmation prompt and proceed with updates automatically", +) +@click.option( + "--log-file", + "-l", + default="update.log", + help="Path to the log file where logs will be saved", + type=str, +) +@click.argument("packages-path", type=click.Path(exists=True), required=False) +def main( + max_workers: int, + keep_going: bool, + commit: bool, + no_confirm: bool, + log_file: str, + packages_path: str, +) -> None: + logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", + handlers=[logging.FileHandler(log_file), logging.StreamHandler(sys.stderr)], + ) + + if packages_path: + with open(packages_path) as f: + packages = json.load(f) + else: + # Read packages from stdin + packages = json.load(sys.stdin) + + logging.info("") + logging.info("Going to be running update for following packages:") + for package in packages: + logging.info(f" - {package['name']}") + logging.info("") + + if not no_confirm and not sys.stdin.isatty(): + confirm = input("Press Enter key to continue...") + if confirm != "": + logging.info("Aborting!") + sys.exit(130) + + logging.info("Running update for:") + asyncio.run(start_updates(max_workers, keep_going, commit, packages)) + logging.info("Packages updated!") + sys.exit() + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + # Let’s cancel outside of the main loop too. + sys.exit(130) diff --git a/maintainers/scripts/update/update.sh b/maintainers/scripts/update/update.sh new file mode 100755 index 00000000..8d070e38 --- /dev/null +++ b/maintainers/scripts/update/update.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +set -e + +rootDir="$(git rev-parse --show-toplevel)" +updateScript="maintainers/scripts/update/update.nix" + +nix-shell "${rootDir}/${updateScript}" \ + --argstr flakePath "${rootDir}" \ + --argstr keep-going 'true' \ + --argstr max-workers "4" \ + --argstr no-confirm "true" \ + --argstr commit 'true' diff --git a/pkgs/besu/update.sh b/pkgs/besu/update.sh new file mode 100644 index 00000000..fac436cb --- /dev/null +++ b/pkgs/besu/update.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p curl jq nix sd + +set -e + +pname="besu" +dirname="$(dirname "$0")" +rootDir="$(git -C "$dirname" rev-parse --show-toplevel)" + +updateVersion() { + local version=$1 + sd "version = \"[0-9.]*\";" "version = \"$version\";" "${dirname}/default.nix" +} + +updateHash() { + local version=$1 + local url="https://hyperledger.jfrog.io/hyperledger/${pname}-binaries/${pname}/${version}/${pname}-${version}.tar.gz" + local sriHash=$(nix store prefetch-file --json "$url" | jq -r '.hash') + sd 'hash = "[a-zA-Z0-9/+-=]*";' "hash = \"$sriHash\";" "${dirname}/default.nix" +} + +currentVersion=$(nix derivation show "${rootDir}#${pname}" | jq -r '.[].env.version') +latestVersion=$(curl -s "https://hyperledger.jfrog.io/artifactory/api/search/latestVersion?g=org.hyperledger.besu.internal&a=besu") + +if [[ "$currentVersion" == "$latestVersion" ]]; then + echo "${pname} is up to date: ${currentVersion}" + exit 0 +fi + +echo "Updating ${pname} from ${currentVersion} to ${latestVersion}" + +updateVersion "$latestVersion" +updateHash "$latestVersion" diff --git a/pkgs/charon/default.nix b/pkgs/charon/default.nix index 5f6185d9..68ca0fc7 100644 --- a/pkgs/charon/default.nix +++ b/pkgs/charon/default.nix @@ -3,6 +3,7 @@ buildGoModule, fetchFromGitHub, mcl, + nix-update-script, }: buildGoModule rec { pname = "charon"; @@ -23,6 +24,10 @@ buildGoModule rec { subPackages = ["."]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Charon (pronounced 'kharon') is a Proof of Stake Ethereum Distributed Validator Client"; homepage = "https://github.com/ObolNetwork/charon"; diff --git a/pkgs/default.nix b/pkgs/default.nix index 1402c42b..7dc82396 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -39,17 +39,17 @@ eth2-val-tools = callPackage ./eth2-val-tools {inherit bls mcl;}; eth-validator-watcher = callPackage2311 ./eth-validator-watcher {}; ethdo = callPackage ./ethdo {inherit bls mcl;}; - ethereal = callPackage ./ethereal {inherit bls mcl;}; + ethereal = callPackage ./ethereal {}; evmc = callPackage ./evmc {}; foundry = callPackageUnstable ./foundry {}; - foundry-bin = inputs.foundry-nix.defaultPackage.${system}.overrideAttrs (_oldAttrs: { - # TODO: Uncomment when https://github.com/shazow/foundry.nix/issues/23 - # meta.platforms = [system]; - meta.platforms = ["x86_64-linux" "aarch64-linux"]; - }); + # foundry-bin = inputs.foundry-nix.defaultPackage.${system}.overrideAttrs (_oldAttrs: { + # # TODO: Uncomment when https://github.com/shazow/foundry.nix/issues/23 + # # meta.platforms = [system]; + # meta.platforms = ["x86_64-linux" "aarch64-linux"]; + # }); geth = callPackage ./geth {}; geth-sealer = callPackage ./geth-sealer {}; - heimdall = callPackage ./heimdall {}; + heimdall-rs = callPackage ./heimdall-rs {}; lighthouse = callPackageUnstable ./lighthouse {inherit foundry;}; mcl = callPackage ./mcl {}; mev-boost = callPackage ./mev-boost {inherit blst;}; diff --git a/pkgs/dirk/default.nix b/pkgs/dirk/default.nix index 1972e883..48d427bb 100644 --- a/pkgs/dirk/default.nix +++ b/pkgs/dirk/default.nix @@ -3,6 +3,7 @@ fetchFromGitHub, mcl, bls, + nix-update-script, }: buildGoModule rec { pname = "dirk"; @@ -22,6 +23,10 @@ buildGoModule rec { doCheck = false; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "An Ethereum 2 distributed remote keymanager, focused on security and long-term performance of signing operations"; homepage = "https://github.com/attestantio/dirk"; diff --git a/pkgs/dreamboat/default.nix b/pkgs/dreamboat/default.nix index d2adf867..1cb1c407 100644 --- a/pkgs/dreamboat/default.nix +++ b/pkgs/dreamboat/default.nix @@ -2,6 +2,7 @@ blst, buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "dreamboat"; @@ -22,6 +23,10 @@ buildGoModule rec { ldflags = ["-s" "-w"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "An Ethereum 2.0 Relay for proposer-builder separation (PBS) with MEV-boost"; homepage = "https://github.com/blocknative/dreamboat"; diff --git a/pkgs/eigenlayer/default.nix b/pkgs/eigenlayer/default.nix index 823d4730..ace51850 100644 --- a/pkgs/eigenlayer/default.nix +++ b/pkgs/eigenlayer/default.nix @@ -2,6 +2,7 @@ lib, buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "eigenlayer"; @@ -19,6 +20,10 @@ buildGoModule rec { ldflags = ["-s" "-w"]; subPackages = ["cmd/eigenlayer"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "Utility manages core operator functionalities like local key management, operator registration and updates"; homepage = "https://www.eigenlayer.xyz/"; diff --git a/pkgs/erigon/default.nix b/pkgs/erigon/default.nix index fa72d793..a97152c3 100644 --- a/pkgs/erigon/default.nix +++ b/pkgs/erigon/default.nix @@ -1,6 +1,7 @@ { buildGoModule, fetchFromGitHub, + nix-update-script, subPackages ? ["cmd/erigon" "cmd/evm" "cmd/rpcdaemon" "cmd/rlpdump"], }: buildGoModule rec { @@ -28,6 +29,11 @@ buildGoModule rec { ldflags = ["-extldflags \"-Wl,--allow-multiple-definition\""]; inherit subPackages; + # TODO: find out why nix-update can't update the package + # passthru.updateScript = nix-update-script { + # extraArgs = ["--flake"]; + # }; + meta = { description = "Ethereum node implementation focused on scalability and modularity"; homepage = "https://github.com/ledgerwatch/erigon/"; diff --git a/pkgs/eth2-testnet-genesis/default.nix b/pkgs/eth2-testnet-genesis/default.nix index dc405aa4..9b475029 100644 --- a/pkgs/eth2-testnet-genesis/default.nix +++ b/pkgs/eth2-testnet-genesis/default.nix @@ -2,6 +2,7 @@ bls, buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "eth2-testnet-genesis"; @@ -22,6 +23,10 @@ buildGoModule rec { ldflags = ["-s" "-w"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Create a genesis state for an Eth2 testnet"; homepage = "https://github.com/protolambda/eth2-testnet-genesis"; diff --git a/pkgs/eth2-val-tools/default.nix b/pkgs/eth2-val-tools/default.nix index 00a1f30f..d83185f3 100644 --- a/pkgs/eth2-val-tools/default.nix +++ b/pkgs/eth2-val-tools/default.nix @@ -1,11 +1,11 @@ { + bls, buildGoModule, - fetchFromGitHub, clang, - mcl, - bls, + fetchFromGitHub, lib, - ... + mcl, + nix-update-script, }: buildGoModule rec { pname = "eth2-val-tools"; @@ -26,6 +26,10 @@ buildGoModule rec { doCheck = false; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "Some experimental tools to manage validators"; homepage = "https://github.com/protolambda/eth2-val-tools"; diff --git a/pkgs/ethdo/default.nix b/pkgs/ethdo/default.nix index e9479f85..78fbca87 100644 --- a/pkgs/ethdo/default.nix +++ b/pkgs/ethdo/default.nix @@ -1,11 +1,11 @@ { + bls, buildGoModule, - fetchFromGitHub, clang, - mcl, - bls, + fetchFromGitHub, lib, - ... + mcl, + nix-update-script, }: buildGoModule rec { pname = "ethdo"; @@ -26,6 +26,10 @@ buildGoModule rec { doCheck = false; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "A command-line tool for managing common tasks in Ethereum 2"; homepage = "https://github.com/wealdtech/ethdo"; diff --git a/pkgs/ethereal/default.nix b/pkgs/ethereal/default.nix index 5fabec1a..ed3fdd17 100644 --- a/pkgs/ethereal/default.nix +++ b/pkgs/ethereal/default.nix @@ -2,7 +2,7 @@ buildGoModule, fetchFromGitHub, lib, - ... + nix-update-script, }: buildGoModule rec { pname = "ethereal"; @@ -19,6 +19,10 @@ buildGoModule rec { doCheck = false; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "A command-line tool for managing common tasks in Ethereum"; homepage = "https://github.com/wealdtech/ethereal/"; diff --git a/pkgs/geth-sealer/default.nix b/pkgs/geth-sealer/default.nix index 77eedac6..a9c650e5 100644 --- a/pkgs/geth-sealer/default.nix +++ b/pkgs/geth-sealer/default.nix @@ -2,7 +2,7 @@ buildGoModule, fetchFromGitHub, lib, - ... + nix-update-script, }: buildGoModule rec { pname = "geth-sealer"; @@ -26,6 +26,10 @@ buildGoModule rec { # Following upstream: https://github.com/ethereum/go-ethereum/blob/v1.10.23/build/ci.go#L218 tags = ["urfave_cli_no_docs"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "Geth Sealer implementation"; homepage = "https://github.com/manifoldfinance/geth-sealer"; diff --git a/pkgs/geth/default.nix b/pkgs/geth/default.nix index 7e002357..c95bacde 100644 --- a/pkgs/geth/default.nix +++ b/pkgs/geth/default.nix @@ -2,7 +2,7 @@ buildGoModule, fetchFromGitHub, lib, - ... + nix-update-script, }: let # A list of binaries to put into separate outputs bins = [ @@ -62,6 +62,10 @@ in # Following upstream: https://github.com/ethereum/go-ethereum/blob/v1.10.23/build/ci.go#L218 tags = ["urfave_cli_no_docs"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "Official golang implementation of the Ethereum protocol"; homepage = "https://geth.ethereum.org/"; diff --git a/pkgs/heimdall/default.nix b/pkgs/heimdall-rs/default.nix similarity index 84% rename from pkgs/heimdall/default.nix rename to pkgs/heimdall-rs/default.nix index c9a14115..db1a1722 100644 --- a/pkgs/heimdall/default.nix +++ b/pkgs/heimdall-rs/default.nix @@ -6,14 +6,15 @@ pkg-config, rustPlatform, stdenv, + nix-update-script, }: rustPlatform.buildRustPackage rec { - pname = "heimdall"; + pname = "heimdall-rs"; version = "0.7.3"; src = fetchFromGitHub { owner = "jon-becker"; - repo = "${pname}-rs"; + repo = pname; rev = version; hash = "sha256-E3WFJ+1ps5UiA+qzJAjouBR4wJbzxrJfvcW6Kany/jU="; }; @@ -39,11 +40,16 @@ rustPlatform.buildRustPackage rec { # tested in upstream CI. doCheck = false; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { description = "A toolkit for EVM bytecode analysis"; homepage = "https://heimdall.rs"; license = [licenses.mit]; mainProgram = "heimdall"; platforms = platforms.unix; + ethereum-nix = true; }; } diff --git a/pkgs/mev-boost-builder/default.nix b/pkgs/mev-boost-builder/default.nix index 8bae5423..6970554f 100644 --- a/pkgs/mev-boost-builder/default.nix +++ b/pkgs/mev-boost-builder/default.nix @@ -2,6 +2,7 @@ blst, buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "builder"; @@ -22,6 +23,10 @@ buildGoModule rec { ldflags = ["-s" "-w"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Flashbots mev-boost block builder"; homepage = "https://github.com/flashbots/builder"; diff --git a/pkgs/mev-boost-relay/default.nix b/pkgs/mev-boost-relay/default.nix index 85e74732..bc6e94dd 100644 --- a/pkgs/mev-boost-relay/default.nix +++ b/pkgs/mev-boost-relay/default.nix @@ -2,6 +2,7 @@ blst, buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "mev-boost-relay"; @@ -26,6 +27,10 @@ buildGoModule rec { "-X main.Version=${version}" ]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "MEV-Boost Relay for Ethereum proposer/builder separation (PBS)"; homepage = "https://github.com/flashbots/mev-boost-relay"; diff --git a/pkgs/mev-boost/default.nix b/pkgs/mev-boost/default.nix index bf6f1a30..159080c5 100644 --- a/pkgs/mev-boost/default.nix +++ b/pkgs/mev-boost/default.nix @@ -2,6 +2,7 @@ blst, buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "mev-boost"; @@ -20,6 +21,10 @@ buildGoModule rec { subPackages = ["cmd/mev-boost"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "MEV-Boost allows proof-of-stake Ethereum consensus clients to source blocks from a competitive builder marketplace"; homepage = "https://github.com/flashbots/mev-boost"; diff --git a/pkgs/prysm/default.nix b/pkgs/prysm/default.nix index e5eee347..11777f91 100644 --- a/pkgs/prysm/default.nix +++ b/pkgs/prysm/default.nix @@ -4,6 +4,7 @@ buildGo121Module, fetchFromGitHub, libelf, + nix-update-script, }: buildGo121Module rec { pname = "prysm"; @@ -35,6 +36,11 @@ buildGo121Module rec { "-X github.com/prysmaticlabs/prysm/v4/runtime/version.gitTag=v${version}" ]; + # TODO: find out why nix-update can't update the package + # passthru.updateScript = nix-update-script { + # extraArgs = ["--flake"]; + # }; + meta = { description = "Go implementation of Ethereum proof of stake"; homepage = "https://github.com/prysmaticlabs/prysm"; diff --git a/pkgs/rocketpool/default.nix b/pkgs/rocketpool/default.nix index c6b00f30..8001af38 100644 --- a/pkgs/rocketpool/default.nix +++ b/pkgs/rocketpool/default.nix @@ -1,6 +1,7 @@ { buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "rocketpool"; @@ -21,6 +22,10 @@ buildGoModule rec { mv $out/bin/rocketpool-cli $out/bin/rocketpool ''; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Rocket Pool CLI"; homepage = "https://github.com/rocket-pool/smartnode"; diff --git a/pkgs/sedge/default.nix b/pkgs/sedge/default.nix index 688456c5..c7bc7f9c 100644 --- a/pkgs/sedge/default.nix +++ b/pkgs/sedge/default.nix @@ -4,6 +4,7 @@ fetchFromGitHub, mcl, mockgen, + nix-update-script, }: let pname = "sedge"; version = "1.3.1"; @@ -32,8 +33,14 @@ in "-w" "-X github.com/NethermindEth/sedge/internal/utils.Version=v${version}" ]; + subPackages = ["cmd/sedge"]; + # TODO: find out why nix-update can't update the package + # passthru.updateScript = nix-update-script { + # extraArgs = ["--flake"]; + # }; + meta = { description = "A one-click setup tool for PoS network/chain validators and nodes."; homepage = "https://docs.sedge.nethermind.io/"; diff --git a/pkgs/ssvnode/default.nix b/pkgs/ssvnode/default.nix index 0b7fc6e7..2021ba56 100644 --- a/pkgs/ssvnode/default.nix +++ b/pkgs/ssvnode/default.nix @@ -3,6 +3,7 @@ mcl, buildGo120Module, fetchFromGitHub, + nix-update-script, }: buildGo120Module rec { pname = "ssv"; @@ -21,6 +22,10 @@ buildGo120Module rec { subPackages = ["cmd/ssvnode"]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Secret-Shared-Validator(SSV) for ethereum staking"; homepage = "https://github.com/bloxapp/ssv"; diff --git a/pkgs/staking-deposit-cli/default.nix b/pkgs/staking-deposit-cli/default.nix index f728df60..ee61ee5d 100644 --- a/pkgs/staking-deposit-cli/default.nix +++ b/pkgs/staking-deposit-cli/default.nix @@ -1,9 +1,9 @@ { autoPatchelfHook, fetchurl, + nix-update-script, stdenv, zlib, - ... }: stdenv.mkDerivation rec { pname = "staking-deposit-cli"; @@ -27,6 +27,10 @@ stdenv.mkDerivation rec { runHook postInstall ''; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Secure key generation for deposits"; homepage = "https://github.com/ethereum/staking-deposit-cli"; diff --git a/pkgs/teku/default.nix b/pkgs/teku/default.nix index c3cd6049..a68cd83f 100644 --- a/pkgs/teku/default.nix +++ b/pkgs/teku/default.nix @@ -24,6 +24,9 @@ stdenv.mkDerivation rec { wrapProgram $out/bin/${pname} --set JAVA_HOME "${jre}" ''; + # TODO: fix the update script + #passthru.updateScript = ./update.sh; + meta = with lib; { description = "Java Implementation of the Ethereum 2.0 Beacon Chain"; homepage = "https://github.com/ConsenSys/teku"; diff --git a/pkgs/teku/update.sh b/pkgs/teku/update.sh new file mode 100755 index 00000000..0575b223 --- /dev/null +++ b/pkgs/teku/update.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env nix-shell +#!nix-shell -i bash -p curl jq nix sd + +set -e + +pname="teku" +dirname="$(dirname "$0")}" +rootDir="$(git -C "$dirname" rev-parse --show-toplevel)" + +updateVersion() { + local version=$1 + sd "version = \"[0-9.]*\";" "version = \"$version\";" "${dirname}/default.nix" +} + +updateHash() { + local version=$1 + local url="https://artifacts.consensys.net/public/${pname}/raw/names/${pname}.tar.gz/versions/${version}/${pname}-${version}.tar.gz" + local sriHash=$(nix store prefetch-file --json "$url" | jq -r '.hash') + sd 'hash = "[a-zA-Z0-9/+-=]*";' "hash = \"$sriHash\";" "${dirname}/default.nix" +} + +currentVersion=$(nix derivation show "${rootDir}#${pname}" | jq -r '.[].env.version') +latestVersion=$(curl -s "https://api.github.com/repos/ConsenSys/teku/releases/latest" | jq -r '.tag_name') + +if [[ "$currentVersion" == "$latestVersion" ]]; then + echo "${pname} is up to date: ${currentVersion}" + exit 0 +fi + +echo "Updating ${pname} from ${currentVersion} to ${latestVersion}" + +updateVersion "$latestVersion" +updateHash "$latestVersion" + diff --git a/pkgs/tx-fuzz/default.nix b/pkgs/tx-fuzz/default.nix index 49a34c8c..0ddf86d9 100644 --- a/pkgs/tx-fuzz/default.nix +++ b/pkgs/tx-fuzz/default.nix @@ -2,6 +2,7 @@ buildGoModule, fetchFromGitHub, lib, + nix-update-script, }: buildGoModule rec { pname = "tx-fuzz"; @@ -22,6 +23,10 @@ buildGoModule rec { mv $out/bin/livefuzzer $out/bin/tx-fuzz ''; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = with lib; { homepage = "https://github.com/MariusVanDerWijden/tx-fuzz"; description = "TX-Fuzz is a package containing helpful functions to create random transactions"; diff --git a/pkgs/vouch/default.nix b/pkgs/vouch/default.nix index 5648d369..cf4da261 100644 --- a/pkgs/vouch/default.nix +++ b/pkgs/vouch/default.nix @@ -1,8 +1,9 @@ { + bls, buildGoModule, fetchFromGitHub, mcl, - bls, + nix-update-script, }: buildGoModule rec { pname = "vouch"; @@ -23,6 +24,10 @@ buildGoModule rec { doCheck = false; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "An Ethereum 2 multi-node validator client"; homepage = "https://github.com/attestantio/vouch"; diff --git a/pkgs/zcli/default.nix b/pkgs/zcli/default.nix index b53fbec9..3905dc91 100644 --- a/pkgs/zcli/default.nix +++ b/pkgs/zcli/default.nix @@ -1,6 +1,7 @@ { buildGoModule, fetchFromGitHub, + nix-update-script, }: buildGoModule rec { pname = "zcli"; @@ -17,6 +18,10 @@ buildGoModule rec { subPackages = ["."]; + passthru.updateScript = nix-update-script { + extraArgs = ["--flake"]; + }; + meta = { description = "Eth2 CLI debugging tool"; homepage = "https://github.com/protolambda/zcli";