From 3bf62e6eb8bf6e55de23d4b7c063506ec5978ea0 Mon Sep 17 00:00:00 2001 From: Yoshitomo Nakanishi Date: Wed, 29 Jul 2026 12:47:02 +0900 Subject: [PATCH] Isolate contest runner artifacts (cherry picked from commit 2b2eeebb09dfbc12bf7c4b513b0bba9c81142ef5) --- contest.sh | 44 ++++-- run_contests.sh | 2 + scripts/test_contest_concurrency.sh | 208 ++++++++++++++++++++++++++++ 3 files changed, 243 insertions(+), 11 deletions(-) create mode 100755 scripts/test_contest_concurrency.sh diff --git a/contest.sh b/contest.sh index 607f56fea..e8e3ebdf4 100755 --- a/contest.sh +++ b/contest.sh @@ -25,9 +25,6 @@ test_dir=$(dirname $file) build_dir="$root_dir/build" base=$(basename "$file" .json) src="$test_dir/$base.solc" -hull="$build_dir/output1.hull" -hexfile="$build_dir/$base.hex" -yulfile="$build_dir/$base.yul" create=true # Allow overriding testrunner location (useful for Nix builds) @@ -87,16 +84,41 @@ suite=$(echo $presuite | tr -d '"') echo "Compiling to Hull..." # Allow overriding sol-core command (useful for Nix builds) : ${SOLCORE_CMD:="cabal run exe:sol-core --"} -if ! $SOLCORE_CMD -f "$src"; then +mkdir -p "$build_dir" +work_root="$build_dir/.contest-work" +mkdir -p "$work_root" +work_dir="$(mktemp -d "$work_root/run.XXXXXX")" +work_marker="$work_dir/.owned-by-contest" +touch "$work_marker" +hull="$work_dir/output1.hull" +yulfile="$work_dir/output.yul" +hexfile="$work_dir/output.hex" +runner_input="$work_dir/runner-input.json" +runner_output="$work_dir/runner-output.json" + +cleanup_work_dir() { + if [[ -z "${work_dir:-}" ]]; then + return + fi + + if [[ "$work_dir" != "$work_root"/run.* || ! -f "$work_marker" ]]; then + echo "Error: refusing to clean unverified contest work directory '$work_dir'" >&2 + return 1 + fi + + rm -rf -- "$work_dir" +} + +trap cleanup_work_dir EXIT +trap 'exit 129' HUP +trap 'exit 130' INT +trap 'exit 143' TERM + +if ! $SOLCORE_CMD -f "$src" -o "$work_dir"; then echo "Error: sol-core compilation failed" exit 1 fi -mkdir -p "$build_dir" -if ls ./output*.hull 1> /dev/null 2>&1; then - mv ./output*.hull "$build_dir"/ -fi - if [[ ! -f "$hull" ]]; then echo "Error: sol-core did not produce output1.hull" exit 1 @@ -122,6 +144,6 @@ fi echo "Hex output: $hexfile" -jq ".$suite.bytecode |= \"$(cat $hexfile)\" " $file > $build_dir/$suite.json +jq ".$suite.bytecode |= \"$(cat $hexfile)\" " $file > "$runner_input" -"$testrunner_exe" "$evmone" "$build_dir/$suite.json" "$build_dir/$suite-output.json" +"$testrunner_exe" "$evmone" "$runner_input" "$runner_output" diff --git a/run_contests.sh b/run_contests.sh index 60a7705cb..b928a3d75 100755 --- a/run_contests.sh +++ b/run_contests.sh @@ -5,6 +5,8 @@ set -euo pipefail root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$root_dir" +bash ./scripts/test_contest_concurrency.sh + bash ./contest.sh test/examples/dispatch/basic.json bash ./contest.sh test/examples/dispatch/assembly.json bash ./contest.sh test/examples/dispatch/neg.json diff --git a/scripts/test_contest_concurrency.sh b/scripts/test_contest_concurrency.sh new file mode 100755 index 000000000..f87506efb --- /dev/null +++ b/scripts/test_contest_concurrency.sh @@ -0,0 +1,208 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +tmp_parent="${TMPDIR:-/tmp}" +tmp_parent="${tmp_parent%/}" +test_root="$(mktemp -d "$tmp_parent/solcore-contest-concurrency.XXXXXX")" +test_marker="$test_root/.owned-by-contest-concurrency-test" +touch "$test_marker" + +cleanup_test_root() { + if [[ "$test_root" != "$tmp_parent"/solcore-contest-concurrency.* || ! -f "$test_marker" ]]; then + echo "Error: refusing to clean unverified test directory '$test_root'" >&2 + return 1 + fi + + rm -rf -- "$test_root" +} + +trap cleanup_test_root EXIT +trap 'exit 129' HUP +trap 'exit 130' INT +trap 'exit 143' TERM + +mkdir -p \ + "$test_root/cases/alpha" \ + "$test_root/cases/beta" \ + "$test_root/fake-bin" \ + "$test_root/state" +cp "$repo_root/contest.sh" "$test_root/contest.sh" +chmod +x "$test_root/contest.sh" + +printf '%s\n' alpha > "$test_root/cases/alpha/shared.solc" +printf '%s\n' '{"shared": {}}' > "$test_root/cases/alpha/shared.json" +printf '%s\n' beta > "$test_root/cases/beta/shared.solc" +printf '%s\n' '{"shared": {}}' > "$test_root/cases/beta/shared.json" +printf '%s\n' user-owned-sentinel > "$test_root/output1.hull" +touch "$test_root/libevmone.so" + +# Nix sandboxes do not provide /usr/bin/env, so use the active Bash path. +printf '#!%s\n\n' "$BASH" > "$test_root/fake-bin/tool" +cat >> "$test_root/fake-bin/tool" <<'EOF' +set -euo pipefail + +tool="$(basename "$0")" + +case "$tool" in + sol-core) + src= + output_dir= + while [[ $# -gt 0 ]]; do + case "$1" in + -f) + src="$2" + shift 2 + ;; + -o) + output_dir="$2" + shift 2 + ;; + *) + shift + ;; + esac + done + + case_name="$FAKE_CASE" + [[ "$(<"$src")" == "$case_name" ]] + printf '%s\n' "$case_name" > "$output_dir/output1.hull" + printf '%s\n' "$output_dir" > "$FAKE_STATE/$case_name.work-dir" + touch "$FAKE_STATE/compiler-$case_name.ready" + + deadline=$((SECONDS + 10)) + until [[ -f "$FAKE_STATE/compiler-alpha.ready" && -f "$FAKE_STATE/compiler-beta.ready" ]]; do + if (( SECONDS >= deadline )); then + echo "Timed out waiting for both fake compilers" >&2 + exit 1 + fi + sleep 0.01 + done + ;; + yule) + hull="$1" + shift + output= + while [[ $# -gt 0 ]]; do + case "$1" in + -o) + output="$2" + shift 2 + ;; + *) + shift + ;; + esac + done + + case_name="$(<"$hull")" + printf '%s\n' "$output" > "$FAKE_STATE/$case_name.yul-path" + printf '%s\n' "$case_name" > "$output" + ;; + solc) + yul= + for arg in "$@"; do + yul="$arg" + done + case_name="$(<"$yul")" + [[ "$case_name" == "$FAKE_CASE" ]] + printf '%s\n' "$yul" > "$FAKE_STATE/$case_name.solc-input" + printf '%s\n' "Binary representation:" "hex-$case_name" + ;; + jq) + if [[ "$1" == "keys[0]" ]]; then + printf '%s\n' '"shared"' + else + [[ "$1" == *"hex-$FAKE_CASE"* ]] + printf '{"shared":{"bytecode":"%s","case":"%s"}}\n' \ + "hex-$FAKE_CASE" "$FAKE_CASE" + fi + ;; + testrunner) + [[ -f "$1" ]] + [[ -f "$2" ]] + command grep -q "\"case\":\"$FAKE_CASE\"" "$2" + printf '%s\n' "$2" > "$FAKE_STATE/$FAKE_CASE.runner-input" + printf '%s\n' "$3" > "$FAKE_STATE/$FAKE_CASE.runner-output" + printf '{"ok":true,"case":"%s"}\n' "$FAKE_CASE" > "$3" + ;; + *) + echo "Unexpected fake tool name: $tool" >&2 + exit 1 + ;; +esac +EOF + +chmod +x "$test_root/fake-bin/tool" +for tool in sol-core yule solc jq testrunner; do + ln -s tool "$test_root/fake-bin/$tool" +done + +run_case() { + local case_name="$1" + + PATH="$test_root/fake-bin:$PATH" \ + SOLCORE_CMD="$test_root/fake-bin/sol-core" \ + YULE_CMD="$test_root/fake-bin/yule" \ + testrunner_exe="$test_root/fake-bin/testrunner" \ + evmone="$test_root/libevmone.so" \ + FAKE_STATE="$test_root/state" \ + FAKE_CASE="$case_name" \ + bash "$test_root/contest.sh" \ + "$test_root/cases/$case_name/shared.json" \ + > "$test_root/state/$case_name.log" 2>&1 +} + +run_case alpha & +alpha_pid=$! +run_case beta & +beta_pid=$! + +failed=0 +if ! wait "$alpha_pid"; then + command cat "$test_root/state/alpha.log" >&2 + failed=1 +fi +if ! wait "$beta_pid"; then + command cat "$test_root/state/beta.log" >&2 + failed=1 +fi +if [[ "$failed" != "0" ]]; then + exit 1 +fi + +alpha_work_dir="$(<"$test_root/state/alpha.work-dir")" +beta_work_dir="$(<"$test_root/state/beta.work-dir")" +alpha_yul_path="$(<"$test_root/state/alpha.yul-path")" +beta_yul_path="$(<"$test_root/state/beta.yul-path")" +alpha_solc_input="$(<"$test_root/state/alpha.solc-input")" +beta_solc_input="$(<"$test_root/state/beta.solc-input")" +alpha_runner_input="$(<"$test_root/state/alpha.runner-input")" +beta_runner_input="$(<"$test_root/state/beta.runner-input")" +alpha_runner_output="$(<"$test_root/state/alpha.runner-output")" +beta_runner_output="$(<"$test_root/state/beta.runner-output")" + +[[ "$alpha_work_dir" == "$test_root/build/.contest-work/run."* ]] +[[ "$beta_work_dir" == "$test_root/build/.contest-work/run."* ]] +[[ "$alpha_work_dir" != "$beta_work_dir" ]] +[[ "$alpha_yul_path" == "$alpha_work_dir/output.yul" ]] +[[ "$beta_yul_path" == "$beta_work_dir/output.yul" ]] +[[ "$alpha_yul_path" != "$beta_yul_path" ]] +[[ "$alpha_solc_input" == "$alpha_yul_path" ]] +[[ "$beta_solc_input" == "$beta_yul_path" ]] +[[ "$alpha_runner_input" == "$alpha_work_dir/runner-input.json" ]] +[[ "$beta_runner_input" == "$beta_work_dir/runner-input.json" ]] +[[ "$alpha_runner_input" != "$beta_runner_input" ]] +[[ "$alpha_runner_output" == "$alpha_work_dir/runner-output.json" ]] +[[ "$beta_runner_output" == "$beta_work_dir/runner-output.json" ]] +[[ "$alpha_runner_output" != "$beta_runner_output" ]] +[[ ! -e "$alpha_work_dir" ]] +[[ ! -e "$beta_work_dir" ]] +[[ "$(<"$test_root/output1.hull")" == "user-owned-sentinel" ]] +[[ ! -e "$test_root/build/shared.yul" ]] +[[ ! -e "$test_root/build/shared.hex" ]] +[[ ! -e "$test_root/build/shared.json" ]] +[[ ! -e "$test_root/build/shared-output.json" ]] + +printf '%s\n' "contest concurrency regression passed"