mirror of
https://github.com/zooai/node.git
synced 2026-10-30 14:48:50 +00:00
388 lines
19 KiB
Docker
388 lines
19 KiB
Docker
# syntax=docker/dockerfile:1.26@sha256:ecfaec9ed6d810b56388c508f4121597bfbba70d41a6dfeee4d8cad5f295fc32
|
|
#
|
|
# zood — the Zoo network node, compiled from source.
|
|
#
|
|
# zood is lux-cpp/node run on Zoo's specs (src/zood.cpp, genesis/), and cevm
|
|
# is the EVM plugin its chain runs in. Every source it compiles is fetched here
|
|
# at a commit pinned below:
|
|
#
|
|
# luxcrypto luxfi/crypto `make dist`: libluxcrypto.a, the ML-DSA-65 and
|
|
# ML-KEM-768 of the post-quantum peer handshake, as a Go c-archive
|
|
# builder AWS-LC, cevm's Conan dependencies, the consensus engine, cevm and
|
|
# lux-cpp/node, then zood and cevm
|
|
# runtime gcr.io/distroless/cc-debian12:nonroot and the two binaries
|
|
#
|
|
# What is not pinned by commit resolves when the image is built: Debian's
|
|
# packages, Conan's Python dependencies, the intx, nlohmann_json and cmake
|
|
# packages from ConanCenter, and blst v0.3.14, which lux-crypto's kzg build
|
|
# clones by tag for its headers.
|
|
#
|
|
# Private repositories are read with the BuildKit secret GH_READ_TOKEN, a GitHub
|
|
# token that can read them. It is never an ARG and never a file. Only the two
|
|
# steps that fetch mount it, and they run git and nothing else: git takes it as
|
|
# configuration from their environment, and each fails if the token is anywhere
|
|
# in the filesystem it leaves. The steps that run other people's code, Conan's
|
|
# above all, do not mount it; that keeps it from them only where the builder
|
|
# isolates one step's processes from the daemon that holds the secret.
|
|
#
|
|
# Every Debian here is 12, the runtime's. A binary carries the glibc symbol
|
|
# versions it was linked against; linked against a newer glibc it builds, it
|
|
# pushes, and it dies on first exec in distroless-debian12.
|
|
#
|
|
# Nothing here names an architecture. The runner builds each platform on a node
|
|
# of that platform, and this file compiles for whichever it is on.
|
|
|
|
# ── pins ────────────────────────────────────────────────────────────────────
|
|
# Full commit SHAs, each checked to be on the branch or tag its fetch line
|
|
# names, spelled in full: a bare `main` would also match a tag called main. GitHub serves any commit it still holds by SHA, including ones no
|
|
# branch reaches any more and ones that only exist in a fork.
|
|
|
|
# run(spec) and the EVM run as a plugin. zood serves /v1/chain/zoo and
|
|
# /v1/chain/200200, 404s /v1/chain/c, and binds --rpc-host (127.0.0.1 unless
|
|
# told otherwise), so a pod passes --rpc-host 0.0.0.0.
|
|
ARG LUX_CPP_NODE=e5f44d164a04656ef8590f4cf5f2ddc805cb6749
|
|
ARG LUX_CPP_CONSENSUS=9928599fc95d92c54b759468a351af907ab29aed
|
|
# cevm main, the tree lux-cpp/node's tests pass on and its own image builds
|
|
# against. Not the integrate/fixes/fix-* branches: those are unmerged GPU-EVM
|
|
# work, and this is the CPU build.
|
|
ARG LUX_CPP_CEVM=6b227e78c3819a866748bf87aac2eae836227dfa
|
|
# The evmc commit cevm's submodule names, fetched where the submodule goes.
|
|
ARG LUX_CPP_EVMC=7cb4b0ca30df7b036d1a582196af5e9a1455a47d
|
|
# The tree lux-cpp/node's last green image built. The commit after it on main
|
|
# adds bcc to CMake's algorithm list and not to the Conan recipe's exports, so
|
|
# the package it makes cannot configure.
|
|
ARG LUX_CPP_CRYPTO=87e59776b97e9e13f1f07ee4deb129f9cda8cff8
|
|
ARG LUX_CPP_BLST=0bf3bb96c630d7451b8549d1ad95074997a5a5e3
|
|
ARG LUX_CPP_ZAP=2a37db5a574f73d972c8c22e5d79b6b24dcbe637
|
|
ARG LUX_GPU_KERNELS=76cdda14b381f77cc42d81c094460bbce6bcb3d1
|
|
# lux-crypto's CMake FetchContent dependencies, at the commits its tags name.
|
|
ARG LUX_CPP_INTX=0306b495820a5259563e5055f0a8b726b9ae4e0b
|
|
ARG LUX_CPP_EVMMAX=9af2f9ac9b45fef6d547e59a06ea091f64966700
|
|
ARG LUX_CPP_PQCLEAN=826eff8124946a005c189eaf2aba5d2a3df8329a
|
|
ARG LUX_CPP_ED25519_DONNA=805dc05f47d3dfaa574cea16fd78321d63b6b17d
|
|
ARG LUX_CPP_BLAKE3_REFERENCE=38173020aa1f643c904f8f0f0340e16f31f01cfc
|
|
ARG LUXFI_C_KZG_4844=9763b8f10ea45221f383e6f6500b78eb4e4ad748
|
|
ARG LUXFI_SR25519_CRUST=0cb4dc4d96e20c4b3dd6d520a43544ea55921ec4
|
|
# The last luxfi/crypto whose go directive golang:1.26.8 builds. main after it
|
|
# moves the directive to 1.27.1 and changes no Go source.
|
|
ARG LUXFI_CRYPTO=923186d4163bf15acf537f96b679a1f7f7915a64
|
|
ARG AWS_LC=7b627926398b6bb786296132b22dbb37bab7649f
|
|
|
|
# ── fetch ───────────────────────────────────────────────────────────────────
|
|
# Sourced by every step that fetches. It holds no secret.
|
|
FROM scratch AS scripts
|
|
COPY <<'EOF' /fetch.sh
|
|
# auth: read access to GitHub for the rest of this RUN, from GH_READ_TOKEN.
|
|
# git reads it as configuration from its environment (GIT_CONFIG_COUNT, see
|
|
# git-config(1)), so no file records it — not .git/config, not ~/.gitconfig,
|
|
# not a layer. It is sent to https://github.com/ and to no other host.
|
|
auth() {
|
|
if [ -r /run/secrets/GH_READ_TOKEN ]; then
|
|
token=$(tr -d '[:space:]' < /run/secrets/GH_READ_TOKEN)
|
|
else
|
|
token=
|
|
fi
|
|
if [ -z "$token" ]; then
|
|
echo "zood: the build secret GH_READ_TOKEN is missing. It is a GitHub token that can read the private lux-cpp, lux-gpu and luxfi repositories this build fetches; pass it as --secret id=GH_READ_TOKEN." >&2
|
|
exit 1
|
|
fi
|
|
header=$(printf 'x-access-token:%s' "$token" | base64 -w0)
|
|
export GIT_CONFIG_COUNT=1 \
|
|
GIT_CONFIG_KEY_0=http.https://github.com/.extraheader \
|
|
GIT_CONFIG_VALUE_0="AUTHORIZATION: basic $header"
|
|
}
|
|
|
|
# sealed: refuses the layer if the token, bare or as the header, is in any file
|
|
# on this filesystem, /run/secrets aside, where the secret itself is mounted. A
|
|
# file that cannot be read refuses it too: unread is not clean.
|
|
sealed() {
|
|
set --
|
|
for d in /* /.[!.]* /run/*; do
|
|
case $d in
|
|
/proc | /sys | /dev | /run | /run/secrets) ;;
|
|
*) [ -e "$d" ] && [ ! -L "$d" ] && set -- "$@" "$d" ;;
|
|
esac
|
|
done
|
|
found=0
|
|
grep -rqF -D skip -e "$token" -e "$header" -- "$@" || found=$?
|
|
case $found in
|
|
0) echo "zood: the GitHub token was written into this layer; it is refused." >&2
|
|
exit 1 ;;
|
|
1) ;;
|
|
*) echo "zood: could not read every file this layer holds; it is refused." >&2
|
|
exit 1 ;;
|
|
esac
|
|
}
|
|
|
|
# fetch <owner/repo> <refs/heads/… or refs/tags/…> <sha> <dir>: the one
|
|
# commit, by its full SHA, with no history, after proving it is on that branch
|
|
# or tag. The proof reads commits only, in a repository of its own that is then
|
|
# removed.
|
|
fetch() {
|
|
repo=$1 ref=$2 sha=$3 dir=$4
|
|
if ! printf '%s' "$sha" | grep -Eqx '[0-9a-f]{40}'; then
|
|
echo "zood: $repo is pinned to '$sha', which is not a full commit SHA." >&2
|
|
exit 1
|
|
fi
|
|
case $ref in
|
|
refs/heads/?* | refs/tags/?*) ;;
|
|
*) echo "zood: $repo is checked against '$ref', which is not a full branch or tag ref." >&2
|
|
exit 1 ;;
|
|
esac
|
|
log=$(mktemp -d)
|
|
git init -q --bare "$log"
|
|
git -C "$log" remote add origin "https://github.com/$repo"
|
|
git -C "$log" fetch -q --filter=tree:0 origin "$ref"
|
|
if ! git -C "$log" rev-list FETCH_HEAD | grep -qx "$sha"; then
|
|
echo "zood: $repo $sha is not on $ref." >&2
|
|
exit 1
|
|
fi
|
|
rm -rf "$log"
|
|
git init -q "$dir"
|
|
git -C "$dir" remote add origin "https://github.com/$repo"
|
|
git -C "$dir" fetch -q --depth 1 origin "$sha"
|
|
git -C "$dir" checkout -q --detach FETCH_HEAD
|
|
test "$(git -C "$dir" rev-parse HEAD)" = "$sha"
|
|
}
|
|
EOF
|
|
|
|
# ── luxcrypto ───────────────────────────────────────────────────────────────
|
|
# A Go c-archive, so Go builds it and the C++ stage takes the archive. Public
|
|
# sources and modules: this stage is given no token.
|
|
FROM golang:1.26.8-bookworm@sha256:a688600ca24f8a4d3ca77f95b0dd40704a9fc787c826660eb7ba0b641b8b175d AS luxcrypto
|
|
COPY --from=scripts /fetch.sh /usr/local/lib/fetch.sh
|
|
ARG LUXFI_CRYPTO
|
|
RUN <<'EOF'
|
|
set -eu
|
|
. /usr/local/lib/fetch.sh
|
|
fetch luxfi/crypto refs/heads/main "$LUXFI_CRYPTO" /src/lux/crypto
|
|
cd /src/lux/crypto
|
|
go mod download github.com/luxfi/accel
|
|
make dist
|
|
test -s dist/libluxcrypto.a
|
|
EOF
|
|
|
|
# ── builder ─────────────────────────────────────────────────────────────────
|
|
FROM debian:bookworm-slim@sha256:3783cc01769c7b2b1b83a5c5ad96c815348e28ed7da68e2e3687004faa906251 AS builder
|
|
|
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build git ca-certificates go-md2man golang-go perl \
|
|
nlohmann-json3-dev python3 python3-pip python3-venv \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# cevm resolves intx, blst, lux-crypto and lux-zap-core through Conan.
|
|
RUN python3 -m venv /opt/conan && /opt/conan/bin/pip install --no-cache-dir conan==2.32.0
|
|
ENV PATH=/opt/conan/bin:$PATH
|
|
|
|
COPY --from=scripts /fetch.sh /usr/local/lib/fetch.sh
|
|
|
|
# AWS-LC: the TLS 1.3 + X25519MLKEM768 the peer link runs on. Static, built once.
|
|
ARG AWS_LC
|
|
RUN <<'EOF'
|
|
set -eu
|
|
. /usr/local/lib/fetch.sh
|
|
fetch aws/aws-lc refs/tags/v1.65.0 "$AWS_LC" /src/aws-lc
|
|
cmake -S /src/aws-lc -B /src/aws-lc-build -G Ninja \
|
|
-DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF -DBUILD_TESTING=OFF
|
|
cmake --build /src/aws-lc-build --target ssl crypto
|
|
EOF
|
|
|
|
# What Conan builds from. lux-crypto's CMake would clone seven more private
|
|
# repositories while it configures, so they are fetched here instead, into
|
|
# /src/deps under their FetchContent names, and the next step points FetchContent
|
|
# at them. evmc goes where cevm's submodule does; cevm refuses to configure
|
|
# without it.
|
|
ARG LUX_CPP_CEVM LUX_CPP_EVMC LUX_CPP_CRYPTO LUX_CPP_BLST LUX_CPP_ZAP \
|
|
LUX_CPP_INTX LUX_CPP_EVMMAX LUX_CPP_PQCLEAN LUX_CPP_ED25519_DONNA \
|
|
LUX_CPP_BLAKE3_REFERENCE LUXFI_C_KZG_4844 LUXFI_SR25519_CRUST
|
|
RUN --mount=type=secret,id=GH_READ_TOKEN <<'EOF'
|
|
set -eu
|
|
. /usr/local/lib/fetch.sh
|
|
auth
|
|
fetch lux-cpp/cevm refs/heads/main "$LUX_CPP_CEVM" /src/luxcpp/cevm
|
|
fetch lux-cpp/evmc refs/heads/main "$LUX_CPP_EVMC" /src/luxcpp/cevm/evmc
|
|
fetch lux-cpp/crypto refs/heads/main "$LUX_CPP_CRYPTO" /src/luxcpp/crypto
|
|
fetch lux-cpp/blst refs/heads/main "$LUX_CPP_BLST" /src/luxcpp/blst
|
|
fetch lux-cpp/zap-cpp-core refs/heads/main "$LUX_CPP_ZAP" /src/luxcpp/zap-cpp-core
|
|
fetch lux-cpp/intx refs/tags/v0.15.0 "$LUX_CPP_INTX" /src/deps/luxcpp_intx
|
|
fetch lux-cpp/evmmax refs/tags/v0.21.0 "$LUX_CPP_EVMMAX" /src/deps/luxcpp_evmmax
|
|
fetch lux-cpp/pqclean refs/tags/v1.0.0 "$LUX_CPP_PQCLEAN" /src/deps/luxcpp_pqclean
|
|
fetch lux-cpp/ed25519-donna refs/tags/v1.0.0 "$LUX_CPP_ED25519_DONNA" /src/deps/luxcpp_ed25519_donna
|
|
fetch lux-cpp/blake3-reference refs/tags/v1.5.0 "$LUX_CPP_BLAKE3_REFERENCE" /src/deps/luxcpp_blake3_reference
|
|
fetch luxfi/c-kzg-4844 refs/tags/v2.1.7 "$LUXFI_C_KZG_4844" /src/deps/luxfi_c_kzg_4844
|
|
fetch luxfi/sr25519-crust refs/tags/v0.2.0 "$LUXFI_SR25519_CRUST" /src/deps/sr25519_crust
|
|
sealed
|
|
EOF
|
|
|
|
# cevm's dependencies, with no token. The lux packages are on no Conan remote,
|
|
# so they are exported from their checkouts first. FetchContent takes each
|
|
# dependency from /src/deps (FETCHCONTENT_SOURCE_DIR_<NAME>) instead of cloning
|
|
# it, and a dependency not fetched there fails rather than being cloned. blst is built portable, choosing ADX at run time, so the binary does not
|
|
# depend on the CPU of the node that happened to build it.
|
|
RUN <<'EOF'
|
|
set -eu
|
|
deps="'FETCHCONTENT_FULLY_DISCONNECTED': {'value': 'ON', 'cache': True, 'type': 'BOOL'}, "
|
|
for d in /src/deps/*; do
|
|
n=$(basename "$d" | tr '[:lower:]' '[:upper:]')
|
|
deps="$deps'FETCHCONTENT_SOURCE_DIR_$n': '$d', "
|
|
done
|
|
conan profile detect --force
|
|
printf 'core.download:parallel=1\n' >> "$(conan config home)/global.conf"
|
|
conan export /src/luxcpp/crypto
|
|
conan export /src/luxcpp/blst
|
|
conan export /src/luxcpp/zap-cpp-core
|
|
conan install /src/luxcpp/cevm \
|
|
-pr /src/luxcpp/cevm/.github/conan/manylinux-relax.profile \
|
|
-s build_type=Release -s compiler.cppstd=gnu20 \
|
|
-o 'bls/*:portable=True' \
|
|
-c "lux-crypto/*:tools.cmake.cmaketoolchain:extra_variables={$deps}" \
|
|
--output-folder=/src/cevm-conan --build=missing
|
|
EOF
|
|
|
|
# The node and the engine under it. gpu-kernels goes where cevm's CMakeLists
|
|
# name it, lux-private/gpu-kernels four levels above lib/evm: it carries the
|
|
# 0x100 precompile's 256-bit arithmetic and the aivm oracle.
|
|
ARG LUX_CPP_CONSENSUS LUX_GPU_KERNELS LUX_CPP_NODE
|
|
RUN --mount=type=secret,id=GH_READ_TOKEN <<'EOF'
|
|
set -eu
|
|
. /usr/local/lib/fetch.sh
|
|
auth
|
|
fetch lux-cpp/consensus refs/heads/main "$LUX_CPP_CONSENSUS" /src/lux-cpp/consensus
|
|
fetch lux-gpu/gpu-kernels refs/heads/main "$LUX_GPU_KERNELS" /src/lux-private/gpu-kernels
|
|
fetch lux-cpp/node refs/heads/main "$LUX_CPP_NODE" /src/lux-cpp/node
|
|
sealed
|
|
EOF
|
|
|
|
# Where lux-cpp/node looks for it: ../../lux/crypto/dist from the top source
|
|
# directory, which is this repository at /src/zooai/node.
|
|
COPY --from=luxcrypto /src/lux/crypto/dist /src/lux/crypto/dist
|
|
|
|
COPY CMakeLists.txt /src/zooai/node/
|
|
COPY src /src/zooai/node/src
|
|
COPY genesis /src/zooai/node/genesis
|
|
|
|
# Release, stripped at link time. Then three checks before anything ships: the
|
|
# binary carries Zoo's name rather than the host's default; it needs no library
|
|
# the runtime lacks (a Conan .so, or a system libssl in place of AWS-LC, would
|
|
# pass here and fail on first exec there); and it runs. --publish on a
|
|
# throwaway directory makes an ML-DSA-65 identity through libluxcrypto's Go
|
|
# runtime and a BLS key, and prints the committee line the BLS key signs.
|
|
RUN <<'EOF'
|
|
set -eu
|
|
cmake -S /src/zooai/node -B /src/build -G Ninja \
|
|
-DCMAKE_TOOLCHAIN_FILE=/src/cevm-conan/build/Release/generators/conan_toolchain.cmake \
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
-DCMAKE_CXX_FLAGS_RELEASE="-O3 -DNDEBUG" \
|
|
-DCMAKE_EXE_LINKER_FLAGS="-s" \
|
|
-DLUX_NODE_DIR=/src/lux-cpp/node \
|
|
-DCONSENSUS_DIR=/src/lux-cpp/consensus \
|
|
-DCEVM_DIR=/src/luxcpp/cevm \
|
|
-DLUXCPP_ROOT=/src/luxcpp \
|
|
-DZAP_DIR=/src/luxcpp/zap-cpp-core/include \
|
|
-DAWSLC_SRC=/src/aws-lc \
|
|
-DAWSLC_BUILD_DIR=/src/aws-lc-build \
|
|
-DBLST_ISA=portable
|
|
cmake --build /src/build --target zood
|
|
z=/src/build/zood
|
|
mkdir -p /out/libexec/lux
|
|
strip -o /out/libexec/lux/cevm "$(find /src/build -type f -name cevm -perm -u+x | head -n1)"
|
|
if ! grep -qF 'zooai/zood/v' "$z"; then
|
|
echo "zood: the binary does not answer as zooai/zood; Zoo's spec did not reach it." >&2
|
|
exit 1
|
|
fi
|
|
for b in "$z" /out/libexec/lux/cevm; do
|
|
needs=$(readelf -d "$b" | sed -n 's/.*(NEEDED).*\[\(.*\)\]$/\1/p')
|
|
test -n "$needs"
|
|
extra=$(printf '%s\n' "$needs" | grep -Evx 'lib(c|m|pthread|dl|rt|resolv|gcc_s|stdc\+\+|gomp)\.so\.[0-9]+|ld-linux-(x86-64|aarch64)\.so\.[0-9]+' || true)
|
|
if [ -n "$extra" ]; then
|
|
echo "zood: $b links $extra, which gcr.io/distroless/cc-debian12 does not carry." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
k=$(mktemp -d)
|
|
"$z" --data "$k" --publish > "$k.line"
|
|
test -s "$k.line"
|
|
rm -rf "$k" "$k.line"
|
|
EOF
|
|
|
|
# ── accept ──────────────────────────────────────────────────────────────────
|
|
# Zoo's history through the door a client uses (`--target accept`). A validator
|
|
# alone, as an archive runs, imports mainnet's export and then testnet's, and
|
|
# four import mainnet's; test/accept.py holds what each serves to the export's
|
|
# own hashes and the Go archive's, and a validator alone to refusing
|
|
# transactions it could never land.
|
|
FROM builder AS accept
|
|
ARG LUXFI_STATE=671e4d6328487e7160f08005dac8590d217bb953
|
|
RUN --mount=type=secret,id=GH_READ_TOKEN <<'EOF'
|
|
set -eu
|
|
. /usr/local/lib/fetch.sh
|
|
auth
|
|
# luxfi/state holds every chain's archive, so only these files' blobs are
|
|
# fetched: the commit and its trees, then each blob, checked against the tree.
|
|
d=$(mktemp -d)
|
|
git init -q "$d"
|
|
git -C "$d" remote add origin https://github.com/luxfi/state
|
|
git -C "$d" fetch -q --filter=tree:0 origin refs/heads/main
|
|
git -C "$d" rev-list FETCH_HEAD | grep -qx "$LUXFI_STATE"
|
|
git -C "$d" fetch -q --depth 1 --filter=blob:none origin "$LUXFI_STATE"
|
|
for net in mainnet-200200 testnet-200201; do
|
|
path=rlp/zoo-${net%-*}/zoo-$net.rlp
|
|
git -C "$d" cat-file blob "$LUXFI_STATE:$path" > /src/zoo-${net%-*}.rlp
|
|
test "$(git hash-object /src/zoo-${net%-*}.rlp)" = "$(git -C "$d" rev-parse "$LUXFI_STATE:$path")"
|
|
done
|
|
rm -rf "$d"
|
|
sealed
|
|
EOF
|
|
COPY test/accept.py /usr/local/lib/accept.py
|
|
RUN <<'EOF'
|
|
set -eu
|
|
z=/src/build/zood
|
|
vm=/out/libexec/lux/cevm
|
|
# The EVM alone first: the plugin replays each export against the genesis zood
|
|
# compiles in, so a refusal is named here rather than behind a validator.
|
|
"$vm" import /src/zooai/node/genesis/mainnet.json /src/zoo-mainnet.rlp
|
|
"$vm" import /src/zooai/node/genesis/testnet.json /src/zoo-testnet.rlp
|
|
# alone NETWORK PORT: a validator alone, as a pod with no shell runs it —
|
|
# publish, then read the line it left — checked, then stopped.
|
|
alone() {
|
|
"$z" --network "$1" --data /tmp/$1 --publish > /dev/null
|
|
"$z" --network "$1" --data /tmp/$1 --committee /tmp/$1/published \
|
|
--peers 127.0.0.1:$(($2 + 1)) --rpc-port "$2" --import-chain-data /src/zoo-$1.rlp \
|
|
--vm "$vm" > /tmp/$1.log 2>&1 &
|
|
pid=$!
|
|
rc=0
|
|
python3 /usr/local/lib/accept.py "$1" 127.0.0.1:"$2" --alone /tmp/$1.log || rc=$?
|
|
kill "$pid" 2>/dev/null || true
|
|
if [ "$rc" -ne 0 ]; then tail -n 30 /tmp/$1.log; exit "$rc"; fi
|
|
}
|
|
alone mainnet 19620
|
|
alone testnet 19610
|
|
# Four, a committee that can decide.
|
|
: > /tmp/committee
|
|
for i in 0 1 2 3; do "$z" --data /tmp/v$i --publish >> /tmp/committee; done
|
|
peers=127.0.0.1:19631,127.0.0.1:19641,127.0.0.1:19651,127.0.0.1:19661
|
|
for i in 0 1 2 3; do
|
|
"$z" --data /tmp/v$i --committee /tmp/committee --peers "$peers" \
|
|
--rpc-port $((19630 + 10 * i)) --import-chain-data /src/zoo-mainnet.rlp \
|
|
--vm "$vm" > /tmp/v$i.log 2>&1 &
|
|
done
|
|
rc=0
|
|
python3 /usr/local/lib/accept.py mainnet 127.0.0.1:19630 /tmp/v0.log /tmp/v1.log /tmp/v2.log /tmp/v3.log || rc=$?
|
|
kill $(jobs -p) 2>/dev/null || true
|
|
if [ "$rc" -ne 0 ]; then tail -n 30 /tmp/v*.log; fi
|
|
exit "$rc"
|
|
EOF
|
|
|
|
# ── runtime ─────────────────────────────────────────────────────────────────
|
|
# cc carries exactly the C and C++ runtimes zood links, and no shell, package
|
|
# manager or fetcher: an image that holds a validator's key holds nothing that
|
|
# can be told to fetch and run.
|
|
FROM gcr.io/distroless/cc-debian12:nonroot@sha256:9dac0a79194e45a7da0158a9c6da57b217585af0786db3845d1f0ec1a0dd182f
|
|
COPY --from=builder /src/build/zood /usr/local/bin/zood
|
|
COPY --from=builder /out/libexec/lux/cevm /usr/local/libexec/lux/cevm
|
|
# The JSON-RPC and the validator mesh. A validator is named by the key it proves
|
|
# on every link, so the mesh port is not an admin surface and needs no gate.
|
|
EXPOSE 9630 9631
|
|
USER nonroot
|
|
ENTRYPOINT ["/usr/local/bin/zood"]
|