From be54cc3e2e58b809c3795a2b85e76711cdff2216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Wed, 4 Dec 2024 08:32:24 +0000 Subject: [PATCH] feat: making testnet script write a docker compose file (#10333) Some QoL stuff for our S&P friends. The tutorial can be simplified by using docker compose. Assuming UNIX distros and node installed, this should work out of the box: ```bash npx aztec-spartan install # creates the docker-compose config npx aztec-spartan start/stop/logs/update/etc ``` --- .github/workflows/ci.yml | 13 + .github/workflows/publish-aztec-packages.yml | 12 + spartan/releases/rough-rhino/.gitignore | 176 +++++++++++ spartan/releases/rough-rhino/Earthfile | 101 +++++++ spartan/releases/rough-rhino/README.md | 37 +++ .../releases/rough-rhino/assets/banner.jpeg | Bin 0 -> 68390 bytes spartan/releases/rough-rhino/aztec-spartan.sh | 285 ++++++++++++++++++ .../releases/rough-rhino/create-spartan.sh | 20 ++ spartan/releases/rough-rhino/full-node.sh | 39 --- spartan/releases/rough-rhino/validator.sh | 42 --- 10 files changed, 644 insertions(+), 81 deletions(-) create mode 100644 spartan/releases/rough-rhino/.gitignore create mode 100644 spartan/releases/rough-rhino/Earthfile create mode 100644 spartan/releases/rough-rhino/README.md create mode 100644 spartan/releases/rough-rhino/assets/banner.jpeg create mode 100755 spartan/releases/rough-rhino/aztec-spartan.sh create mode 100755 spartan/releases/rough-rhino/create-spartan.sh delete mode 100755 spartan/releases/rough-rhino/full-node.sh delete mode 100755 spartan/releases/rough-rhino/validator.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27f6df05ded..99625e35fb3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -875,6 +875,19 @@ jobs: timeout-minutes: 40 run: earthly-ci -P --no-output +test --box=${{ matrix.box }} --browser=${{ matrix.browser }} --mode=cache + rough-rhino-installer: + needs: [configure] + runs-on: ${{ needs.configure.outputs.username }}-x86 + steps: + - uses: actions/checkout@v4 + with: { ref: "${{ github.event.pull_request.head.sha }}" } + - uses: ./.github/ci-setup-action + with: + concurrency_key: rough-rhino-installer + - name: Rough Rhino Installer Helper Script + working-directory: ./spartan/releases/rough-rhino + run: earthly-ci +test-all + protocol-circuits-gates-report: needs: [build, configure] if: needs.configure.outputs.non-docs == 'true' && needs.configure.outputs.non-barretenberg-cpp == 'true' diff --git a/.github/workflows/publish-aztec-packages.yml b/.github/workflows/publish-aztec-packages.yml index 2695f252c68..c2fe77d9b88 100644 --- a/.github/workflows/publish-aztec-packages.yml +++ b/.github/workflows/publish-aztec-packages.yml @@ -312,6 +312,18 @@ jobs: --VERSION=$VERSION \ --DRY_RUN=${{ (github.event.inputs.publish == 'false') && '1' || '0' }} + - name: Publish spartan NPM package + run: | + DEPLOY_TAG=${{ env.DEPLOY_TAG }} + VERSION=${DEPLOY_TAG#aztec-packages-v} + earthly-ci \ + --no-output \ + --secret NPM_TOKEN=${{ env.NPM_TOKEN }} \ + ./spartan/releases/rough-rhino+publish-npm \ + --DIST_TAG=latest \ + --VERSION=$VERSION \ + --DRY_RUN=${{ (github.event.inputs.publish == 'false') && '1' || '0' }} + publish-aztec-up: needs: [configure, publish-manifests] runs-on: ubuntu-latest diff --git a/spartan/releases/rough-rhino/.gitignore b/spartan/releases/rough-rhino/.gitignore new file mode 100644 index 00000000000..23ce2843a4a --- /dev/null +++ b/spartan/releases/rough-rhino/.gitignore @@ -0,0 +1,176 @@ +# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore + +# Logs + +logs +_.log +npm-debug.log_ +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Caches + +.cache + +# Diagnostic reports (https://nodejs.org/api/report.html) + +report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json + +# Runtime data + +pids +_.pid +_.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover + +lib-cov + +# Coverage directory used by tools like istanbul + +coverage +*.lcov + +# nyc test coverage + +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) + +.grunt + +# Bower dependency directory (https://bower.io/) + +bower_components + +# node-waf configuration + +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) + +build/Release + +# Dependency directories + +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) + +web_modules/ + +# TypeScript cache + +*.tsbuildinfo + +# Optional npm cache directory + +.npm + +# Optional eslint cache + +.eslintcache + +# Optional stylelint cache + +.stylelintcache + +# Microbundle cache + +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history + +.node_repl_history + +# Output of 'npm pack' + +*.tgz + +# Yarn Integrity file + +.yarn-integrity + +# dotenv environment variable files + +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) + +.parcel-cache + +# Next.js build output + +.next +out + +# Nuxt.js build / generate output + +.nuxt +dist + +# Gatsby files + +# Comment in the public line in if your project uses Gatsby and not Next.js + +# https://nextjs.org/blog/next-9-1#public-directory-support + +# public + +# vuepress build output + +.vuepress/dist + +# vuepress v2.x temp and cache directory + +.temp + +# Docusaurus cache and generated files + +.docusaurus + +# Serverless directories + +.serverless/ + +# FuseBox cache + +.fusebox/ + +# DynamoDB Local files + +.dynamodb/ + +# TernJS port file + +.tern-port + +# Stores VSCode versions used for testing VSCode extensions + +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +# IntelliJ based IDEs +.idea + +# Finder (MacOS) folder config +.DS_Store +docker-compose.yml diff --git a/spartan/releases/rough-rhino/Earthfile b/spartan/releases/rough-rhino/Earthfile new file mode 100644 index 00000000000..53e1f6365a7 --- /dev/null +++ b/spartan/releases/rough-rhino/Earthfile @@ -0,0 +1,101 @@ +VERSION 0.7 + +FROM ubuntu:22.04 +WORKDIR /app + +deps: + RUN apt-get update && apt-get install -y \ + curl \ + git \ + make \ + nodejs \ + npm \ + unzip + +test-setup: + FROM +deps + COPY aztec-spartan.sh . + RUN chmod +x aztec-spartan.sh + # Mock docker and docker compose commands for testing + RUN mkdir -p /usr/local/bin && \ + echo '#!/bin/bash\necho "Docker command: $@"' > /usr/local/bin/docker && \ + echo '#!/bin/bash\necho "Docker compose command: $@"' > /usr/local/bin/docker-compose && \ + chmod +x /usr/local/bin/docker /usr/local/bin/docker-compose + +test-help: + FROM +test-setup + RUN ./aztec-spartan.sh | grep -q "Commands:" && \ + echo "✅ Help command test passed" || \ + (echo "❌ Help command test failed" && exit 1) + +test-no-config: + FROM +test-setup + RUN if ./aztec-spartan.sh start 2>&1 | grep -q "Configuration not found"; then \ + echo "✅ No config test passed"; \ + else \ + echo "❌ No config test failed" && exit 1; \ + fi + +test-install: + FROM +test-setup + # Test installation with CLI arguments + RUN echo -e "\n\n" | ./aztec-spartan.sh config \ + -p 8080 \ + -p2p 40400 \ + -ip 1.2.3.4 \ + -k 0x00 \ + -n test-validator + # Verify docker-compose.yml was created and contains correct values + RUN test -f docker-compose.yml && \ + grep -q "name: test-validator" docker-compose.yml && \ + grep -q "P2P_UDP_ANNOUNCE_ADDR=1.2.3.4:40400" docker-compose.yml && \ + grep -q "AZTEC_PORT=8080" docker-compose.yml && \ + grep -q "VALIDATOR_PRIVATE_KEY=0x00" docker-compose.yml && \ + echo "✅ Config test passed" || \ + (echo "❌ Config test failed" && exit 1) + +test-docker-check: + FROM +deps + COPY aztec-spartan.sh . + RUN chmod +x aztec-spartan.sh + # Remove docker to test docker installation check + RUN rm -f /usr/local/bin/docker /usr/local/bin/docker-compose + # Test docker check (should fail since docker is not installed) + RUN if ./aztec-spartan.sh config 2>&1 | grep -q "Docker or Docker Compose not found"; then \ + echo "✅ Docker check test passed"; \ + else \ + echo "❌ Docker check test failed" && exit 1; \ + fi + +test-start-stop: + FROM +test-setup + # First install with test configuration + RUN echo -e "\n\n" | ./aztec-spartan.sh config \ + -p 8080 \ + -p2p 40400 \ + -ip 1.2.3.4 \ + -k 0x00 \ + -n test-validator + # Test start command + RUN ./aztec-spartan.sh start 2>&1 | grep -q "Starting containers" && \ + echo "✅ Start command test passed" || \ + (echo "❌ Start command test failed" && exit 1) + # Test stop command + RUN ./aztec-spartan.sh stop 2>&1 | grep -q "Stopping containers" && \ + echo "✅ Stop command test passed" || \ + (echo "❌ Stop command test failed" && exit 1) + +test-update: + FROM +test-setup + RUN ./aztec-spartan.sh update 2>&1 | grep -q "Pulling latest images" && \ + echo "✅ Update command test passed" || \ + (echo "❌ Update command test failed" && exit 1) + +test-all: + BUILD +test-help + BUILD +test-no-config + BUILD +test-install + BUILD +test-docker-check + BUILD +test-start-stop + BUILD +test-update + diff --git a/spartan/releases/rough-rhino/README.md b/spartan/releases/rough-rhino/README.md new file mode 100644 index 00000000000..7e64b12a3aa --- /dev/null +++ b/spartan/releases/rough-rhino/README.md @@ -0,0 +1,37 @@ +# Aztec Spartan + +This tool helps easing the entry barrier to boot an Aztec Sequencer and Prover (S&P) Testnet. + +![Aztec Sparta Meme](./assets/banner.jpeg) + +For once, there's no rocket science here. This script does the following: + +- Checks for the presence of Docker in your machine +- Prompts you for some environment variables +- Outputs a templated docker-compose file with your variables +- Runs the docker compose file + +It should work in most UNIX-based machines. + +## Installation + +To configure a new node, create a new directory and run the install script: + +```bash +cd val1 +curl -L https://raw.githubusercontent.com/AztecProtocol/aztec-packages/refs/heads/master/spartan/releases/rough-rhino/create-spartan.sh | bash +``` + +This will install `aztec-spartan.sh` in the current directory. You can now run it: + +```bash +./aztec-spartan.sh config +``` + +If you don't have Docker installed, the script will do it for you. It will then prompt for any required environment variables and output a `docker-compose.yml` file. + +You can run the command without any command to see all available options, and pass them as flags, i.e. `npx aztec-spartan config -p 8080 -p2p 40400 -n nameme`. + +## Running + +To spare you a few keystrokes, you can use `npx aztec-spartan [start/stop/logs/update]` to start, stop, output logs or pull the latest docker images. diff --git a/spartan/releases/rough-rhino/assets/banner.jpeg b/spartan/releases/rough-rhino/assets/banner.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..e91ed867f600d25d3711709e4736e9b691c4b014 GIT binary patch literal 68390 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

~N!*vKtOF`r29<+<} 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 GKmXak4z2D0 literal 0 HcmV?d00001 diff --git a/spartan/releases/rough-rhino/aztec-spartan.sh b/spartan/releases/rough-rhino/aztec-spartan.sh new file mode 100755 index 00000000000..5198a7bf78c --- /dev/null +++ b/spartan/releases/rough-rhino/aztec-spartan.sh @@ -0,0 +1,285 @@ +#!/bin/bash + +# Colors and formatting +BLUE='\033[0;34m' +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Global variables +ARCH=$(uname -m) +DEFAULT_P2P_PORT="40400" +DEFAULT_PORT="8080" +DEFAULT_KEY="0x0000000000000000000000000000000000000000000000000000000000000001" +# Try to get default IP from ipify API, otherwise leave empty to require user input +DEFAULT_IP=$(curl -s --connect-timeout 5 https://api.ipify.org?format=json | grep -o '"ip":"[^"]*' | cut -d'"' -f4 || echo "") +DEFAULT_NAME="validator-1" + +# Parse command line arguments +parse_args() { + while [[ $# -gt 0 ]]; do + case $1 in + -p|--port) + CLI_PORT="$2" + shift 2 + ;; + -p2p|--p2p-port) + CLI_P2P_PORT="$2" + shift 2 + ;; + -ip|--ip) + CLI_IP="$2" + shift 2 + ;; + -k|--key) + CLI_KEY="$2" + shift 2 + ;; + -n|--name) + CLI_NAME="$2" + shift 2 + ;; + *) + shift + ;; + esac + done +} + +# Show banner function +show_banner() { + echo -e "${BLUE}" + echo " _ ____ _____ _____ ____ _____ _____ ____ _____ _ _ _____ _____ " + echo " / \ |_ /|_ _| ____| _ \ |_ _| ____/ ___|_ _| \ | | ____|_ _|" + echo " / _ \ / / | | | _| | |_) | | | | _| \___ \ | | | \| | _| | | " + echo " / ___ \/ /_ | | | |___| _ < | | | |___ ___) || | | |\ | |___ | | " + echo "/_/ \_\____| |_| |_____|_| \_\ |_| |_____|____/ |_| |_| \_|_____| |_| " + echo -e "${NC}" +} + +# Check if Docker is installed +check_docker() { + echo -e "${BLUE}Checking Docker installation...${NC}" + if command -v docker >/dev/null 2>&1 && command -v docker compose >/dev/null 2>&1; then + echo -e "${GREEN}Docker and Docker Compose are installed${NC}" + return 0 + else + echo -e "${RED}Docker or Docker Compose not found${NC}" + read -p "Would you like to install Docker? [Y/n] " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]] || [[ -z $REPLY ]]; then + install_docker + return $? + fi + return 1 + fi +} + +# Install Docker +install_docker() { + echo -e "${BLUE}Installing Docker...${NC}" + if curl -fsSL https://get.docker.com | sh; then + sudo usermod -aG docker $USER + echo -e "${GREEN}Docker installed successfully${NC}" + echo -e "${YELLOW}Please log out and back in for group changes to take effect${NC}" + return 0 + else + echo -e "${RED}Failed to install Docker${NC}" + return 1 + fi +} + +# Get public IP +get_public_ip() { + echo -e "${BLUE}Fetching public IP...${NC}" + PUBLIC_IP=$(curl -s https://api.ipify.org?format=json | grep -o '"ip":"[^"]*' | cut -d'"' -f4) + if [ -n "$PUBLIC_IP" ]; then + echo -e "${GREEN}Public IP: $PUBLIC_IP${NC}" + return 0 + else + echo -e "${YELLOW}Failed to get public IP${NC}" + return 1 + fi +} + +# Configure environment +configure_environment() { + local args=("$@") + parse_args "${args[@]}" + + echo -e "${BLUE}Configuring environment...${NC}" + + # Use CLI arguments if provided, otherwise use defaults or prompt + if [ -n "$CLI_NAME" ]; then + NAME="$CLI_NAME" + else + read -p "Validator Name [$DEFAULT_NAME]: " NAME + NAME=${NAME:-$DEFAULT_NAME} + fi + + if [ -n "$CLI_P2P_PORT" ]; then + P2P_PORT="$CLI_P2P_PORT" + else + read -p "P2P Port [$DEFAULT_P2P_PORT]: " P2P_PORT + P2P_PORT=${P2P_PORT:-$DEFAULT_P2P_PORT} + fi + + if [ -n "$CLI_PORT" ]; then + PORT="$CLI_PORT" + else + read -p "Node Port [$DEFAULT_PORT]: " PORT + PORT=${PORT:-$DEFAULT_PORT} + fi + + if [ -n "$CLI_KEY" ]; then + KEY="$CLI_KEY" + else + while true; do + read -p "Validator Private Key: " KEY + if [ -z "$KEY" ]; then + echo -e "${RED}Error: Validator Private Key is required${NC}" + else + break + fi + done + fi + + if [ -n "$CLI_IP" ]; then + IP="$CLI_IP" + else + if [ -z "$DEFAULT_IP" ]; then + while true; do + read -p "Public IP: " IP + if [ -z "$IP" ]; then + echo -e "${RED}Error: Public IP is required${NC}" + else + break + fi + done + else + read -p "Public IP [$DEFAULT_IP]: " IP + IP=${IP:-$DEFAULT_IP} + fi + fi + + # Generate docker-compose.yml + cat > docker-compose.yml << EOF +name: ${NAME} +services: + validator: + network_mode: host + restart: unless-stopped + environment: + - P2P_UDP_ANNOUNCE_ADDR=${IP}:${P2P_PORT} + - P2P_TCP_ANNOUNCE_ADDR=${IP}:${P2P_PORT} + - COINBASE=0xbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + - VALIDATOR_DISABLED=false + - VALIDATOR_PRIVATE_KEY=${KEY} + - SEQ_PUBLISHER_PRIVATE_KEY=${KEY} + - L1_PRIVATE_KEY=${KEY} + - DEBUG=aztec:*,-aztec:avm_simulator*,-aztec:circuits:artifact_hash,-aztec:libp2p_service,-json-rpc*,-aztec:world-state:database,-aztec:l2_block_stream* + - LOG_LEVEL=debug + - AZTEC_PORT=${PORT} + - P2P_ENABLED=true + - L1_CHAIN_ID=1337 + - PROVER_REAL_PROOFS=true + - PXE_PROVER_ENABLED=true + - ETHEREUM_SLOT_DURATION=12sec + - AZTEC_SLOT_DURATION=36 + - AZTEC_EPOCH_DURATION=32 + - AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS=13 + - ETHEREUM_HOST=http://34.48.76.131:8545 + - BOOTSTRAP_NODES=enr:-Jq4QO_3szmgtG2cbEdnFDIhpGAQkc1HwfNy4-M6sG9QmQbPTmp9PMOHR3xslfR23hORiU-GpA7uM9uXw49lFcnuuvYGjWF6dGVjX25ldHdvcmsBgmlkgnY0gmlwhCIwTIOJc2VjcDI1NmsxoQKQTN17XKCwjYSSwmTc-6YzCMhd3v6Ofl8TS-WunX6LCoN0Y3CCndCDdWRwgp3Q + - REGISTRY_CONTRACT_ADDRESS=0x5fbdb2315678afecb367f032d93f642f64180aa3 + - GOVERNANCE_PROPOSER_CONTRACT_ADDRESS=0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0 + - FEE_JUICE_CONTRACT_ADDRESS=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512 + - ROLLUP_CONTRACT_ADDRESS=0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6 + - REWARD_DISTRIBUTOR_CONTRACT_ADDRESS=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 + - GOVERNANCE_CONTRACT_ADDRESS=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 + - COIN_ISSUER_CONTRACT_ADDRESS=0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 + - FEE_JUICE_PORTAL_CONTRACT_ADDRESS=0x0165878a594ca255338adfa4d48449f69242eb8f + - INBOX_CONTRACT_ADDRESS=0xed179b78d5781f93eb169730d8ad1be7313123f4 + - OUTBOX_CONTRACT_ADDRESS=0x1016b5aaa3270a65c315c664ecb238b6db270b64 + - P2P_UDP_LISTEN_ADDR=0.0.0.0:${P2P_PORT} + - P2P_TCP_LISTEN_ADDR=0.0.0.0:${P2P_PORT} + image: aztecprotocol/aztec:698cd3d62680629a3f1bfc0f82604534cedbccf3-${ARCH} + command: start --node --archiver --sequencer +EOF + + echo -e "${GREEN}Configuration complete! Use './aztec-spartan.sh start' to launch your node.${NC}" +} + +# Docker commands +start_node() { + if [ ! -f "docker-compose.yml" ]; then + echo -e "${RED}Configuration not found. Please run './aztec-spartan.sh config' first.${NC}" + exit 1 + fi + echo -e "${BLUE}Starting containers...${NC}" + if docker compose up -d; then + echo -e "${GREEN}Containers started successfully${NC}" + else + echo -e "${RED}Failed to start containers${NC}" + exit 1 + fi +} + +stop_node() { + echo -e "${BLUE}Stopping containers...${NC}" + if docker compose down; then + echo -e "${GREEN}Containers stopped successfully${NC}" + else + echo -e "${RED}Failed to stop containers${NC}" + exit 1 + fi +} + +update_node() { + echo -e "${BLUE}Pulling latest images...${NC}" + if docker compose pull; then + echo -e "${GREEN}Images updated successfully${NC}" + else + echo -e "${RED}Failed to update images${NC}" + exit 1 + fi +} + +show_logs() { + echo -e "${BLUE}Fetching logs...${NC}" + if ! docker compose logs -f; then + echo -e "${RED}Failed to fetch logs${NC}" + exit 1 + fi +} + +# Main script +case "$1" in + "config") + show_banner + check_docker + configure_environment "$@" + ;; + "start") + start_node + ;; + "stop") + stop_node + ;; + "update") + update_node + ;; + "logs") + show_logs + ;; + *) + echo "Usage: $0 {config|start|stop|update|logs}" + echo "Commands:" + echo " config - Install and configure Aztec Testnet node" + echo " start - Start Aztec Testnet node" + echo " stop - Stop Aztec Testnet node" + echo " update - Update Aztec Testnet node images" + echo " logs - Show Aztec Testnet node logs" + exit 1 + ;; +esac diff --git a/spartan/releases/rough-rhino/create-spartan.sh b/spartan/releases/rough-rhino/create-spartan.sh new file mode 100755 index 00000000000..870263926eb --- /dev/null +++ b/spartan/releases/rough-rhino/create-spartan.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# URL of the aztec-spartan.sh script +DEFAULT_URL="https://raw.githubusercontent.com/AztecProtocol/aztec-packages/refs/heads/zpedro/testnet_docker_compose/spartan/releases/rough-rhino/aztec-spartan.sh" + +# Colors for output +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Download the script +echo "Downloading aztec-spartan.sh..." +if curl -L -o aztec-spartan.sh "${1:-$DEFAULT_URL}"; then + chmod +x aztec-spartan.sh + echo -e "${GREEN}✓ aztec-spartan.sh has been downloaded and made executable${NC}" + echo "You can now run it with: ./aztec-spartan.sh" +else + echo -e "${RED}✗ Failed to download aztec-spartan.sh${NC}" + exit 1 +fi diff --git a/spartan/releases/rough-rhino/full-node.sh b/spartan/releases/rough-rhino/full-node.sh deleted file mode 100755 index 75a0d33bca1..00000000000 --- a/spartan/releases/rough-rhino/full-node.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -set -eu - -# get host arch -ARCH=$(uname -m) -IMAGE="aztecprotocol/aztec:698cd3d62680629a3f1bfc0f82604534cedbccf3-${ARCH}" - -docker run --rm --network=host \ - -e P2P_UDP_ANNOUNCE_ADDR=$PUBLIC_IP:$P2P_PORT \ - -e P2P_TCP_ANNOUNCE_ADDR=$PUBLIC_IP:$P2P_PORT \ - -e COINBASE=0xbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ - -e DEBUG="aztec:*,-aztec:avm_simulator*,-aztec:circuits:artifact_hash,-aztec:libp2p_service,-json-rpc*,-aztec:world-state:database,-aztec:l2_block_stream*" \ - -e LOG_LEVEL=debug \ - -e AZTEC_PORT=$NODE_PORT \ - -e P2P_ENABLED=true \ - -e VALIDATOR_DISABLED=true \ - -e L1_CHAIN_ID=1337 \ - -e PROVER_REAL_PROOFS=true \ - -e PXE_PROVER_ENABLED=true \ - -e ETHEREUM_SLOT_DURATION=12sec \ - -e AZTEC_SLOT_DURATION=36 \ - -e AZTEC_EPOCH_DURATION=32 \ - -e AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS=13 \ - -e ETHEREUM_HOST=http://34.48.76.131:8545 \ - -e BOOTSTRAP_NODES=enr:-Jq4QO_3szmgtG2cbEdnFDIhpGAQkc1HwfNy4-M6sG9QmQbPTmp9PMOHR3xslfR23hORiU-GpA7uM9uXw49lFcnuuvYGjWF6dGVjX25ldHdvcmsBgmlkgnY0gmlwhCIwTIOJc2VjcDI1NmsxoQKQTN17XKCwjYSSwmTc-6YzCMhd3v6Ofl8TS-WunX6LCoN0Y3CCndCDdWRwgp3Q \ - -e REGISTRY_CONTRACT_ADDRESS=0x5fbdb2315678afecb367f032d93f642f64180aa3 \ - -e GOVERNANCE_PROPOSER_CONTRACT_ADDRESS=0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0 \ - -e FEE_JUICE_CONTRACT_ADDRESS=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512 \ - -e ROLLUP_CONTRACT_ADDRESS=0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6 \ - -e REWARD_DISTRIBUTOR_CONTRACT_ADDRESS=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 \ - -e GOVERNANCE_CONTRACT_ADDRESS=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 \ - -e COIN_ISSUER_CONTRACT_ADDRESS=0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 \ - -e FEE_JUICE_PORTAL_CONTRACT_ADDRESS=0x0165878a594ca255338adfa4d48449f69242eb8f \ - -e INBOX_CONTRACT_ADDRESS=0xed179b78d5781f93eb169730d8ad1be7313123f4 \ - -e OUTBOX_CONTRACT_ADDRESS=0x1016b5aaa3270a65c315c664ecb238b6db270b64 \ - -e P2P_UDP_LISTEN_ADDR=0.0.0.0:$P2P_PORT \ - -e P2P_TCP_LISTEN_ADDR=0.0.0.0:$P2P_PORT \ - $IMAGE start --node --archiver --sequencer diff --git a/spartan/releases/rough-rhino/validator.sh b/spartan/releases/rough-rhino/validator.sh deleted file mode 100755 index 246e59527bb..00000000000 --- a/spartan/releases/rough-rhino/validator.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -set -eu - -# get host arch -ARCH=$(uname -m) -IMAGE="aztecprotocol/aztec:698cd3d62680629a3f1bfc0f82604534cedbccf3-${ARCH}" - -docker run --rm --network=host \ - -e P2P_UDP_ANNOUNCE_ADDR=$PUBLIC_IP:$P2P_PORT \ - -e P2P_TCP_ANNOUNCE_ADDR=$PUBLIC_IP:$P2P_PORT \ - -e COINBASE=0xbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ - -e VALIDATOR_DISABLED=false \ - -e VALIDATOR_PRIVATE_KEY=$VALIDATOR_PKEY \ - -e SEQ_PUBLISHER_PRIVATE_KEY=$VALIDATOR_PKEY \ - -e L1_PRIVATE_KEY=$VALIDATOR_PKEY \ - -e DEBUG="aztec:*,-aztec:avm_simulator*,-aztec:circuits:artifact_hash,-aztec:libp2p_service,-json-rpc*,-aztec:world-state:database,-aztec:l2_block_stream*" \ - -e LOG_LEVEL=debug \ - -e AZTEC_PORT=$NODE_PORT \ - -e P2P_ENABLED=true \ - -e L1_CHAIN_ID=1337 \ - -e PROVER_REAL_PROOFS=true \ - -e PXE_PROVER_ENABLED=true \ - -e ETHEREUM_SLOT_DURATION=12sec \ - -e AZTEC_SLOT_DURATION=36 \ - -e AZTEC_EPOCH_DURATION=32 \ - -e AZTEC_EPOCH_PROOF_CLAIM_WINDOW_IN_L2_SLOTS=13 \ - -e ETHEREUM_HOST=http://34.48.76.131:8545 \ - -e BOOTSTRAP_NODES=enr:-Jq4QO_3szmgtG2cbEdnFDIhpGAQkc1HwfNy4-M6sG9QmQbPTmp9PMOHR3xslfR23hORiU-GpA7uM9uXw49lFcnuuvYGjWF6dGVjX25ldHdvcmsBgmlkgnY0gmlwhCIwTIOJc2VjcDI1NmsxoQKQTN17XKCwjYSSwmTc-6YzCMhd3v6Ofl8TS-WunX6LCoN0Y3CCndCDdWRwgp3Q \ - -e REGISTRY_CONTRACT_ADDRESS=0x5fbdb2315678afecb367f032d93f642f64180aa3 \ - -e GOVERNANCE_PROPOSER_CONTRACT_ADDRESS=0x9fe46736679d2d9a65f0992f2272de9f3c7fa6e0 \ - -e FEE_JUICE_CONTRACT_ADDRESS=0xe7f1725e7734ce288f8367e1bb143e90bb3f0512 \ - -e ROLLUP_CONTRACT_ADDRESS=0x2279b7a0a67db372996a5fab50d91eaa73d2ebe6 \ - -e REWARD_DISTRIBUTOR_CONTRACT_ADDRESS=0x5fc8d32690cc91d4c39d9d3abcbd16989f875707 \ - -e GOVERNANCE_CONTRACT_ADDRESS=0xcf7ed3acca5a467e9e704c703e8d87f634fb0fc9 \ - -e COIN_ISSUER_CONTRACT_ADDRESS=0xdc64a140aa3e981100a9beca4e685f962f0cf6c9 \ - -e FEE_JUICE_PORTAL_CONTRACT_ADDRESS=0x0165878a594ca255338adfa4d48449f69242eb8f \ - -e INBOX_CONTRACT_ADDRESS=0xed179b78d5781f93eb169730d8ad1be7313123f4 \ - -e OUTBOX_CONTRACT_ADDRESS=0x1016b5aaa3270a65c315c664ecb238b6db270b64 \ - -e P2P_UDP_LISTEN_ADDR=0.0.0.0:$P2P_PORT \ - -e P2P_TCP_LISTEN_ADDR=0.0.0.0:$P2P_PORT \ - $IMAGE start --node --archiver --sequencer