Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
843d3d4
add build.sh, compat.sh
ala-mode Feb 12, 2026
72fe621
add Dockerfile, building
ala-mode Feb 12, 2026
afbf598
update .gitignore
ala-mode Feb 12, 2026
a3d9c32
rm comments
ala-mode Feb 12, 2026
e4e9a32
update comments
ala-mode Feb 12, 2026
3663e99
cleanup
ala-mode Feb 12, 2026
c41119c
add Makefile
ala-mode Feb 12, 2026
67e8ff5
update README
ala-mode Feb 13, 2026
0f50206
cleanup
ala-mode Feb 13, 2026
97e19fd
fix spelling in README
ala-mode Feb 15, 2026
f63aaeb
Merge branch 'zcash:main' into stagex_reproducable_build
ala-mode Feb 26, 2026
1aa0623
build with --all-features, restrict runtime permissions
ala-mode Feb 26, 2026
1ee0a91
add entrypoint.sh
ala-mode Feb 26, 2026
7bd3378
add load_image.sh, update Makefile
ala-mode Feb 26, 2026
9c48fae
add utils dir for scripts
ala-mode Feb 26, 2026
454627b
change runtime stage to busybox base image
ala-mode Feb 26, 2026
c563d24
update Makefile
ala-mode Feb 26, 2026
73736a4
adjust Dockerfile, mv load_image.sh
ala-mode Feb 26, 2026
3ce864e
modify permissions
ala-mode Feb 26, 2026
643f271
add to load_image.sh
ala-mode Feb 26, 2026
459f7db
set WORKDIR, add create wallet to Makefile, functioning stub create_w…
ala-mode Feb 26, 2026
651f636
update create_wallet.sh
ala-mode Feb 27, 2026
ec1872f
mkdir and set container permissions with root, run with user, cleanup
ala-mode Feb 27, 2026
a6ed9a3
cleanup
ala-mode Feb 27, 2026
88db0e5
streamline
ala-mode Feb 27, 2026
8b48e7f
cleanup
ala-mode Feb 27, 2026
5f3027c
add comment
ala-mode Feb 27, 2026
116fb9c
Merge branch 'zcash:main' into stagex_reproducable_build
ala-mode Mar 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
# Guard against accidental commits of the `local` and `tmp` paths
/local
/tmp

#StageX build directory
/build
134 changes: 134 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# syntax=docker/dockerfile:1

# stages:
# - setup: sets default values
# - release: builds release binary
# - export: minimal binary export
# - runtime: prepares the release image
#
# We first set default values for build arguments used across the stages.
# Each stage must define the build arguments (ARGs) it uses.

ARG RUST_VERSION=1.91.1

ARG FEATURES=""

ARG UID=10801
ARG GID=${UID}
ARG USER="user"
ARG HOME="/home/${USER}"
ARG CARGO_HOME="${HOME}/.cargo"
ARG CARGO_TARGET_DIR="${HOME}/target"
ARG TARGET_ARCH="x86_64-unknown-linux-musl"

FROM stagex/core-busybox@sha256:d608daa946e4799cf28b105aba461db00187657bd55ea7c2935ff11dac237e27 AS busybox
FROM stagex/pallet-rust@sha256:4062550919db682ebaeea07661551b5b89b3921e3f3a2b0bc665ddea7f6af1ca AS pallet-rust

# This stage captures build args as env vars
FROM pallet-rust AS setup

SHELL ["/bin/sh", "-xo", "pipefail", "-c"]

# Build arguments and variables
ARG CARGO_INCREMENTAL
# default to 0, disables incremental compilation.
ENV CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-0}

ARG CARGO_HOME
ENV CARGO_HOME=${CARGO_HOME}

# This stage builds the zcash-devtool release binary.
FROM setup AS release

ARG HOME
WORKDIR ${HOME}

ARG CARGO_HOME
ARG CARGO_TARGET_DIR
ARG TARGET_ARCH

ENV RUST_BACKTRACE=1
ENV RUSTFLAGS="-C codegen-units=1"
ENV RUSTFLAGS="${RUSTFLAGS} -C target-feature=+crt-static"
ENV RUSTFLAGS="${RUSTFLAGS} -C link-arg=-Wl,--build-id=none"

ENV SOURCE_DATE_EPOCH=1
ENV CXXFLAGS="-include cstdint"

COPY . .

RUN --mount=type=bind,source=Cargo.toml,target=Cargo.toml,ro \
--mount=type=bind,source=Cargo.lock,target=Cargo.lock,ro \
--mount=type=cache,target=${HOME}/target/ \
--mount=type=cache,target=/usr/local/cargo/registry/ \
--mount=type=cache,target=${CARGO_TARGET_DIR} \
--mount=type=cache,target=${CARGO_HOME} \
cargo fetch --locked --target $TARGET_ARCH && \
cargo metadata --locked --format-version=1 > /dev/null 2>&1

RUN --network=none \
--mount=type=bind,source=Cargo.toml,target=Cargo.toml,ro \
--mount=type=bind,source=Cargo.lock,target=Cargo.lock,ro \
--mount=type=cache,target=${HOME}/target/ \
--mount=type=cache,target=/usr/local/cargo/registry/ \
--mount=type=cache,target=${CARGO_TARGET_DIR} \
--mount=type=cache,target=${CARGO_HOME} \
cargo build --frozen --release --all-features --target ${TARGET_ARCH} && \
install -D -m 0755 ${HOME}/target/${TARGET_ARCH}/release/zcash-devtool /usr/local/bin/zcash-devtool

# This stage is used to export the binary
FROM scratch AS export
COPY --from=release /usr/local/bin/* /

# This stage starts from StageX/busybox and copies the built
# zcash-devtool binary from the `release` stage
FROM busybox AS runtime

ARG FEATURES
ENV FEATURES=${FEATURES}

# Create a non-privileged user for running `zcash-devtool`.
#
# We use a high UID/GID (10801) to avoid overlap with host system users.
# This reduces the risk of container user namespace conflicts with host accounts,
# which could potentially lead to privilege escalation if a container escape occurs.
#
# We do not use the `--system` flag for user creation since:
# 1. System user ranges (100-999) can collide with host system users
# (see: https://github.com/nginxinc/docker-nginx/issues/490)
# 2. There's no value added and warning messages can be raised at build time
# (see: https://github.com/dotnet/dotnet-docker/issues/4624)
#
# The high UID/GID values provide an additional security boundary in containers
# where user namespaces are shared with the host.
ARG UID
ENV UID=${UID}
ARG GID
ENV GID=${GID}
ARG USER
ENV USER=${USER}
ARG HOME
ENV HOME=${HOME}

COPY --chmod=550 <<-EOF /etc/passwd
root:x:0:0:root:/root:/bin/sh
user:x:${UID}:${GID}::${HOME}:/bin/sh
EOF

COPY --chmod=550 <<-EOF /etc/group
root:x:0:
user:x:${GID}:
EOF

USER ${UID}:${GID}

WORKDIR /usr/local/bin

USER root
COPY --from=release /usr/local/bin/zcash-devtool /usr/local/bin/
COPY ./utils/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN mkdir -p /usr/local/bin/zec_sqlite_wallet && chown -R ${UID}:${GID} /usr/local/bin/ && chmod -R 770 /usr/local/bin/ && chmod 550 /usr/local/bin/zcash-devtool
USER $USER

ENTRYPOINT [ "entrypoint.sh" ]
CMD [ "./zcash-devtool" ]
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Simple wrapper for scripts with printed status messages.
#
# Running `make` or `make stagex` will leverage the steps below
# to check compatibility and build the binary via StageX.

.PHONY: stagex compat build load create

stagex: compat build
@echo "stagex build completed via make."

compat:
@echo "Beginning Compatibility Check step."
@./utils/compat.sh
@echo " [PASS] Compatibility Check passed."

build:
@echo "Entering Build step."
@./utils/build.sh
@echo "Build step complete."

load:
@echo "Attempting to load OCI image into local docker image store."
@./utils/load_image.sh
@echo "make load step complete."

create:
@echo "Making zcash-devtool wallet. This requires user input. The docker container's runtime shares the host kernel's entropy source."
@./utils/create_wallet.sh
@echo "Wallet creation script complete."
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,13 @@ scale experimentation, at your own risk.

## Usage

No binary artifacts are provided for this crate; it is generally used via
`cargo run` as follows:
No binary artifacts are directly provided for this crate.

However, a bootstrapped and reproducible build pipeline using StageX is included.
To create a binary, you can simply run `make` in the root directory of the repo.
The resulting binary will be found in the `/build/` directory.

It can also be used via `cargo run` as follows:

To obtain the help docs:
```
Expand Down
32 changes: 32 additions & 0 deletions utils/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!/bin/sh

set -e

DIR="$( cd "$( dirname "$0" )" && pwd )"
REPO_ROOT="$(git rev-parse --show-toplevel)"
PLATFORM="linux/amd64"
OCI_OUTPUT="$REPO_ROOT/build/oci"
DOCKERFILE="$REPO_ROOT/Dockerfile"
NAME=zcash-devtool

export DOCKER_BUILDKIT=1
export SOURCE_DATE_EPOCH=1

echo $DOCKERFILE
mkdir -p $OCI_OUTPUT

# Build runtime image for docker run
echo "Building runtime image..."
docker build -f "$DOCKERFILE" "$REPO_ROOT" \
--platform "$PLATFORM" \
--target runtime \
--output type=oci,rewrite-timestamp=true,force-compression=true,dest=$OCI_OUTPUT/zcash-devtool.tar,name=zcash-devtool \
"$@"

# Extract from export stage
echo "Extracting binaries..."
docker build -f "$DOCKERFILE" "$REPO_ROOT" --quiet \
--platform "$PLATFORM" \
--target export \
--output type=local,dest="$REPO_ROOT/build" \
"$@"
84 changes: 84 additions & 0 deletions utils/compat.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/usr/bin/env bash
set -e
readonly MIN_BASH_VERSION=5
readonly MIN_DOCKER_VERSION=26.0.0
readonly MIN_BUILDX_VERSION=0.13
### Exit with error message
die() {
echo "$@" >&2
exit 1
}

### Bail and instruct user on missing package to install for their platform
die_pkg() {
local -r package=${1?}
local -r version=${2?}
local install_cmd
case "$OSTYPE" in
linux*)
if command -v "apt" >/dev/null; then
install_cmd="apt install ${package}"
elif command -v "yum" >/dev/null; then
install_cmd="yum install ${package}"
elif command -v "pacman" >/dev/null; then
install_cmd="pacman -Ss ${package}"
elif command -v "emerge" >/dev/null; then
install_cmd="emerge ${package}"
elif command -v "nix-env" >/dev/null; then
install_cmd="nix-env -i ${package}"
fi
;;
bsd*) install_cmd="pkg install ${package}" ;;
darwin*) install_cmd="port install ${package}" ;;
*) die "Error: Your operating system is not supported" ;;
esac
echo "Error: ${package} ${version}+ does not appear to be installed." >&2
[ -n "$install_cmd" ] && echo "Try: \`${install_cmd}\`" >&2
exit 1
}

### Check if actual binary version is >= minimum version
check_version(){
local pkg="${1?}"
local have="${2?}"
local need="${3?}"
local i ver1 ver2 IFS='.'
[[ "$have" == "$need" ]] && return 0
read -r -a ver1 <<< "$have"
read -r -a ver2 <<< "$need"
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++));
do ver1[i]=0;
done
for ((i=0; i<${#ver1[@]}; i++)); do
[[ -z ${ver2[i]} ]] && ver2[i]=0
((10#${ver1[i]} > 10#${ver2[i]})) && return 0
((10#${ver1[i]} < 10#${ver2[i]})) && die_pkg "${pkg}" "${need}"
done
}

### Check if required binaries are installed at appropriate versions
check_tools(){
if [ -z "${BASH_VERSINFO[0]}" ] \
|| [ "${BASH_VERSINFO[0]}" -lt "${MIN_BASH_VERSION}" ]; then
die_pkg "bash" "${MIN_BASH_VERSION}"
fi
for cmd in "$@"; do
case $cmd in
buildx)
docker buildx version >/dev/null 2>&1 || die "Error: buildx not found"
version=$(docker buildx version 2>/dev/null | grep -o 'v[0-9.]*' | sed 's/v//')
check_version "buildx" "${version}" "${MIN_BUILDX_VERSION}"
;;
docker)
command -v docker >/dev/null || die "Error: docker not found"
version=$(docker version -f '{{ .Server.Version }}')
check_version "docker" "${version}" "${MIN_DOCKER_VERSION}"
;;
esac
done
}

check_tools docker buildx;
docker info -f '{{ .DriverStatus }}' \
| grep "io.containerd.snapshotter.v1" >/dev/null \
|| die "Error: Docker Engine is not using containerd for image storage"
12 changes: 12 additions & 0 deletions utils/create_wallet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/sh

set -e

echo "Checking local docker image store to see if a zcash-devtool:latest image is present."
# Checks for empty string, discarding error messages.
if [ -z "$(docker images -q zcash-devtool:latest 2>/dev/null)" ]; then
echo "There is no zcash-devtool:latest image listed by docker."
else
echo "Creating wallet. Connecting via clearnet to zecrocks."
docker run -it zcash-devtool:latest ./zcash-devtool wallet init --name "stagex_container_wallet" --identity ./age_id.txt --connection direct --network test -s zecrocks
fi
31 changes: 31 additions & 0 deletions utils/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/bin/sh

# Entrypoint for running zcash-devtool in Docker.
#
# The main script logic is at the bottom.
#
# ## Notes
#
# zcash-devtool is a stateless tool. Each command has some effect:
# inspect
# Intended to be run against "anything zcash" and provide information. For example,
# an address, or a transaction.
# wallet
# Can create and inspect wallets, sync, send zec and so on.

set -eo pipefail

# Main Script Logic
#
# 1. Print environment variables and config for debugging.
# 2. Tests if zcash-devtool runs, printing help.
# 3. Execs the CMD or custom command provided.

echo "INFO: Using the following environment variables:"
printenv

echo "Testing zcash-devtool to print version string:"
./zcash-devtool help

echo "now exec'ing $@ "
exec "$@"
20 changes: 20 additions & 0 deletions utils/load_image.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/sh

set -e

REPO_ROOT="$(git rev-parse --show-toplevel)"
OCI_OUTPUT="$REPO_ROOT/build/oci"
TARBALL="${OCI_OUTPUT}/zcash-devtool.tar"


# Build runtime image for docker run
echo "Checking if the OCI output from build is present."
if [ -f "$TARBALL" ];
then
echo "OCI output file present, loading tar file into local docker image store."
docker load < $TARBALL
echo "...Done!"
else
echo "OCI output file not present."
fi