Files
skunk-net-e2e/wire-batch-operator-local.sh
2026-04-03 17:17:40 -04:00

346 lines
12 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WIRE_SYSIO_DIR="${WIRE_SYSIO_DIR:-${ROOT_DIR}/wire-sysio}"
BUILD_DIR="${WIRE_SYSIO_BUILD_DIR:-${WIRE_SYSIO_DIR}/build/debug-docker}"
VCPKG_DIR="${BUILD_DIR}/vcpkg_installed/x64-linux"
WIRE_CDT_DIR="${WIRE_CDT_DIR:-${ROOT_DIR}/wire-cdt}"
WIRE_CDT_BUILD_DIR="${WIRE_CDT_BUILD_DIR:-${WIRE_CDT_DIR}/build/debug-docker}"
WIRE_SYSIO_SUBMODULE_FALLBACK_DIR="${WIRE_SYSIO_SUBMODULE_FALLBACK_DIR:-${ROOT_DIR}/wire-sysio}"
WIRE_SYSIO_BUILD_FALLBACK_DIR="${WIRE_SYSIO_BUILD_FALLBACK_DIR:-${ROOT_DIR}/wire-sysio/build/debug-docker}"
ROUTE="${1:-${WIRE_BATCH_OPERATOR_ROUTE:-}}"
INDEX="${2:-${WIRE_BATCH_OPERATOR_INDEX:-1}}"
OP_ROOT="${WIRE_BATCH_OPERATOR_ROOT:-/srv/wire-batch-operators}"
WIRE_BATCH_OPERATOR_ARTIFACTS_DIR="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR:-${ROOT_DIR}/.local/e2e}"
CONFIG_DIR="${OP_ROOT}/${ROUTE}/${INDEX}/config"
DATA_DIR="${OP_ROOT}/${ROUTE}/${INDEX}/data"
LOG_DIR="${OP_ROOT}/${ROUTE}/${INDEX}/log"
LOG_FILE="${LOG_DIR}/relay.log"
BUILD_LOCK_FILE="${BUILD_DIR}/batch-operator-relay.lock"
CMAKE_COMMON_ARGS=(
-S "${WIRE_SYSIO_DIR}"
-B "${BUILD_DIR}"
-G Ninja
-DCMAKE_BUILD_TYPE=Debug
-DCMAKE_TOOLCHAIN_FILE="${WIRE_SYSIO_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake"
-DCMAKE_C_COMPILER=/opt/clang/clang-18/bin/clang
-DCMAKE_CXX_COMPILER=/opt/clang/clang-18/bin/clang++
-DCMAKE_INSTALL_PREFIX=/opt/wire
-DCMAKE_PREFIX_PATH="/opt/wire;/opt/clang/clang-18;${WIRE_CDT_BUILD_DIR}"
-DENABLE_TESTS=OFF
-DBUILD_SYSTEM_CONTRACTS=ON
-DBUILD_TEST_CONTRACTS=OFF
-DCDT_ROOT="${WIRE_CDT_BUILD_DIR}"
)
dir_is_empty() {
local path="$1"
[[ -d "${path}" ]] && [[ -z "$(find "${path}" -mindepth 1 -maxdepth 1 -print -quit 2>/dev/null)" ]]
}
link_submodule_from_fallback() {
local relative_path="$1"
local target_path="${WIRE_SYSIO_DIR}/${relative_path}"
local source_path="${WIRE_SYSIO_SUBMODULE_FALLBACK_DIR}/${relative_path}"
local link_source
if [[ ! -e "${source_path}" ]]; then
return
fi
link_source="$(realpath --relative-to "$(dirname "${target_path}")" "${source_path}")"
if [[ -L "${target_path}" ]] && [[ "$(readlink "${target_path}")" == "${link_source}" ]]; then
return
fi
if [[ -L "${target_path}" ]]; then
ln -sfn "${link_source}" "${target_path}"
return
fi
if dir_is_empty "${target_path}"; then
rmdir "${target_path}"
fi
if [[ ! -e "${target_path}" ]]; then
ln -sfn "${link_source}" "${target_path}"
fi
}
hydrate_wire_submodules() {
link_submodule_from_fallback "libraries/appbase"
link_submodule_from_fallback "vcpkg"
}
hydrate_wire_build_cache() {
local target_install_dir="${BUILD_DIR}/vcpkg_installed"
local source_install_dir="${WIRE_SYSIO_BUILD_FALLBACK_DIR}/vcpkg_installed"
local link_source
if [[ ! -d "${source_install_dir}" ]]; then
return
fi
mkdir -p "$(dirname "${target_install_dir}")"
link_source="$(realpath --relative-to "$(dirname "${target_install_dir}")" "${source_install_dir}")"
if [[ -L "${target_install_dir}" ]] && [[ "$(readlink "${target_install_dir}")" == "${link_source}" ]]; then
return
fi
if [[ -L "${target_install_dir}" ]]; then
ln -sfn "${link_source}" "${target_install_dir}"
return
fi
if [[ -d "${target_install_dir}" ]] && [[ ! -f "${BUILD_DIR}/bin/batch-operator-relay" ]]; then
mv "${target_install_dir}" "${target_install_dir}.partial.$(date +%s)"
fi
if [[ ! -e "${target_install_dir}" ]]; then
ln -s "${link_source}" "${target_install_dir}"
fi
}
require_wire_submodules() {
hydrate_wire_submodules
if [[ ! -f "${WIRE_SYSIO_DIR}/vcpkg/bootstrap-vcpkg.sh" ]] || [[ ! -f "${WIRE_SYSIO_DIR}/libraries/appbase/CMakeLists.txt" ]]; then
echo "wire-sysio submodules are missing. Run: git -C ${WIRE_SYSIO_DIR} submodule update --init --recursive" >&2
exit 1
fi
}
write_pkgconfig_shims() {
local pc_dir="$1"
local lib_dir="$2"
mkdir -p "${pc_dir}"
cat >"${pc_dir}/libssl.pc" <<EOF
prefix=${VCPKG_DIR}
exec_prefix=\${prefix}
libdir=${lib_dir}
includedir=${VCPKG_DIR}/include
Name: libssl
Description: BoringSSL compatibility shim for curl configure
Version: 1.0.0
Libs: -L${lib_dir} -lssl
Cflags: -I${VCPKG_DIR}/include
EOF
cat >"${pc_dir}/libcrypto.pc" <<EOF
prefix=${VCPKG_DIR}
exec_prefix=\${prefix}
libdir=${lib_dir}
includedir=${VCPKG_DIR}/include
Name: libcrypto
Description: BoringSSL compatibility shim for curl configure
Version: 1.0.0
Libs: -L${lib_dir} -lbscrypto
Cflags: -I${VCPKG_DIR}/include
EOF
}
configure_wire_sysio() {
mkdir -p "${BUILD_DIR}"
hydrate_wire_build_cache
if [[ ! -x "${WIRE_SYSIO_DIR}/vcpkg/vcpkg" ]]; then
"${WIRE_SYSIO_DIR}/vcpkg/bootstrap-vcpkg.sh"
fi
cmake "${CMAKE_COMMON_ARGS[@]}" >/dev/null 2>&1 || true
write_pkgconfig_shims "${VCPKG_DIR}/lib/pkgconfig" "${VCPKG_DIR}/lib"
write_pkgconfig_shims "${VCPKG_DIR}/debug/lib/pkgconfig" "${VCPKG_DIR}/debug/lib"
cmake \
"${CMAKE_COMMON_ARGS[@]}" \
-DOPENSSL_INCLUDE_DIR="${VCPKG_DIR}/include" \
-DOPENSSL_SSL_LIBRARY="${VCPKG_DIR}/debug/lib/libssl.a" \
-DOPENSSL_CRYPTO_LIBRARY="${VCPKG_DIR}/debug/lib/libbscrypto.a"
}
build_batch_operator() {
cmake --build "${BUILD_DIR}" --target batch-operator-relay -- -j"$(nproc)"
}
require_var() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "Missing required environment variable: ${name}" >&2
exit 1
fi
}
prepare_dirs() {
mkdir -p "${CONFIG_DIR}" "${DATA_DIR}" "${LOG_DIR}"
}
append_log() {
printf '[%s] %s\n' "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" "$*" >>"${LOG_FILE}"
}
configure_and_build_batch_operator() {
mkdir -p "${BUILD_DIR}"
append_log "Waiting for build lock: ${BUILD_LOCK_FILE}"
{
flock 9
append_log "Acquired build lock"
configure_wire_sysio >>"${LOG_FILE}" 2>&1
build_batch_operator >>"${LOG_FILE}" 2>&1
} 9>"${BUILD_LOCK_FILE}"
}
wait_for_artifact() {
local path="$1"
local attempts="${2:-120}"
for _ in $(seq 1 "${attempts}"); do
if [[ -f "${path}" ]]; then
return 0
fi
sleep 1
done
echo "Timed out waiting for artifact: ${path}" >&2
exit 1
}
source_env_file() {
local path="$1"
set -a
# shellcheck disable=SC1090
source "${path}"
set +a
}
load_generated_artifacts() {
local wire_env="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR}/wire.env"
local source_env
wait_for_artifact "${wire_env}"
source_env_file "${wire_env}"
case "${ROUTE}" in
eth)
source_env="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR}/ethereum.env"
;;
sol)
source_env="${WIRE_BATCH_OPERATOR_ARTIFACTS_DIR}/solana.env"
;;
*)
echo "Unsupported route '${ROUTE}'. Expected 'eth' or 'sol'." >&2
exit 1
;;
esac
wait_for_artifact "${source_env}"
source_env_file "${source_env}"
if [[ "${ROUTE}" == "eth" ]]; then
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_RPC_URL="${LOCAL_WIRE_RPC_URL:-http://wire-nodeop:8887}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT="${LOCAL_WIRE_ETH_DEPOT_ACCOUNT:-}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_ACCOUNT="${LOCAL_WIRE_ETH_OPERATOR_ACCOUNT:-}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID="${LOCAL_WIRE_ETH_OPERATOR_PROVIDER_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC="${LOCAL_WIRE_ETH_OPERATOR_PROVIDER_SPEC:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID="${LOCAL_ETH_CLIENT_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID="${LOCAL_ETH_PROVIDER_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC="${LOCAL_ETH_PROVIDER_SPEC:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_RPC_URL="${LOCAL_ETH_RPC_URL:-}"
[[ -n "${WIRE_BATCH_OPERATOR_ETH_ABI_FILE:-}" ]] || WIRE_BATCH_OPERATOR_ETH_ABI_FILE="${LOCAL_ETH_ABI_FILE:-}"
[[ -n "${WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS:-}" ]] || WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS="${LOCAL_ETH_OPP_ADDRESS:-}"
[[ -n "${WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS:-}" ]] || WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS="${LOCAL_ETH_OPP_INBOUND_ADDRESS:-}"
else
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_RPC_URL="${LOCAL_WIRE_RPC_URL:-http://wire-nodeop:8887}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT="${LOCAL_WIRE_SOL_DEPOT_ACCOUNT:-}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_ACCOUNT:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_ACCOUNT="${LOCAL_WIRE_SOL_OPERATOR_ACCOUNT:-}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID="${LOCAL_WIRE_SOL_OPERATOR_PROVIDER_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC="${LOCAL_WIRE_SOL_OPERATOR_PROVIDER_SPEC:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID="${LOCAL_SOL_CLIENT_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID="${LOCAL_SOL_PROVIDER_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC="${LOCAL_SOL_PROVIDER_SPEC:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL:-}" ]] || WIRE_BATCH_OPERATOR_SOURCE_RPC_URL="${LOCAL_SOL_RPC_URL:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID:-}" ]] || WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID="${LOCAL_SOL_PROGRAM_ID:-}"
[[ -n "${WIRE_BATCH_OPERATOR_SOL_IDL_FILE:-}" ]] || WIRE_BATCH_OPERATOR_SOL_IDL_FILE="${LOCAL_SOL_IDL_FILE:-}"
fi
}
build_args() {
local -n out_args=$1
local route="$2"
require_var WIRE_BATCH_OPERATOR_WIRE_ACCOUNT
require_var WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID
require_var WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC
require_var WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID
require_var WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID
require_var WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC
require_var WIRE_BATCH_OPERATOR_SOURCE_RPC_URL
out_args=(
--config-dir "${CONFIG_DIR}"
--data-dir "${DATA_DIR}"
--batch-operator-wire-rpc-url "${WIRE_BATCH_OPERATOR_WIRE_RPC_URL:-http://wire-nodeop:8887}"
--batch-operator-wire-depot-account "${WIRE_BATCH_OPERATOR_WIRE_DEPOT_ACCOUNT:-sysio.depot}"
--batch-operator-wire-operator "${WIRE_BATCH_OPERATOR_WIRE_ACCOUNT},${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_ID}"
--batch-operator-poll-interval-ms "${WIRE_BATCH_OPERATOR_POLL_INTERVAL_MS:-5000}"
--signature-provider "${WIRE_BATCH_OPERATOR_WIRE_PROVIDER_SPEC}"
--signature-provider "${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_SPEC}"
)
if [[ "${route}" == "eth" ]]; then
require_var WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS
require_var WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS
require_var WIRE_BATCH_OPERATOR_ETH_ABI_FILE
out_args+=(
--outpost-ethereum-client "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID},${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID},${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL},${WIRE_BATCH_OPERATOR_ETH_CHAIN_ID:-31337}"
--ethereum-abi-file "${WIRE_BATCH_OPERATOR_ETH_ABI_FILE}"
--batch-operator-ethereum-client-id "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID}"
--batch-operator-ethereum-opp-address "${WIRE_BATCH_OPERATOR_ETH_OPP_ADDRESS}"
--batch-operator-ethereum-opp-inbound-address "${WIRE_BATCH_OPERATOR_ETH_OPP_INBOUND_ADDRESS}"
)
elif [[ "${route}" == "sol" ]]; then
require_var WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID
require_var WIRE_BATCH_OPERATOR_SOL_IDL_FILE
out_args+=(
--outpost-solana-client "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID},${WIRE_BATCH_OPERATOR_SOURCE_PROVIDER_ID},${WIRE_BATCH_OPERATOR_SOURCE_RPC_URL}"
--solana-idl-file "${WIRE_BATCH_OPERATOR_SOL_IDL_FILE}"
--batch-operator-solana-client-id "${WIRE_BATCH_OPERATOR_SOURCE_CLIENT_ID}"
--batch-operator-solana-program-id "${WIRE_BATCH_OPERATOR_SOL_PROGRAM_ID}"
)
else
echo "Unsupported route '${route}'. Expected 'eth' or 'sol'." >&2
exit 1
fi
}
main() {
require_wire_submodules
prepare_dirs
load_generated_artifacts
append_log "Loaded generated artifacts for route=${ROUTE} index=${INDEX}"
configure_and_build_batch_operator
local binary="${BUILD_DIR}/bin/batch-operator-relay"
local args=()
build_args args "${ROUTE}"
append_log "Starting batch-operator route=${ROUTE} index=${INDEX}"
append_log "Config dir: ${CONFIG_DIR}"
append_log "Data dir: ${DATA_DIR}"
exec "${binary}" "${args[@]}" >>"${LOG_FILE}" 2>&1
}
main "$@"