diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml new file mode 100644 index 000000000..9cc8da280 --- /dev/null +++ b/.github/workflows/docker-build.yml @@ -0,0 +1,45 @@ +name: Build and Push Docker Image to GitHub Container Registry + +on: + release: + types: [published] + +jobs: + build: + runs-on: karnot-arc-runner-set + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image to GitHub Container Registry + uses: docker/build-push-action@v4 + with: + context: . + file: ./Dockerfile + push: true + platforms: linux/amd64,linux/arm64 + tags: | + ghcr.io/${{ github.repository_owner }}/madara:latest + ghcr.io/${{ github.repository_owner }}/madara:${{ github.event.release.tag_name }} + labels: | + org.opencontainers.image.source=${{ github.repository.html_url }} + org.opencontainers.image.version=${{ github.event.release.tag_name }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Post successful message + run: echo "Docker image built and pushed successfully" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..7bf2dcfba --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,29 @@ +name: Create Release + +on: + push: + tags: + - "v*.*.*" # Triggers on version tags like v1.0.0 + +permissions: + contents: write + +jobs: + create_release: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Create GitHub Release + uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.RELEASE_ACTION }} + tag: ${{ github.ref_name }} + name: Release ${{ github.ref_name }} + commit: ${{ github.sha }} + draft: false + prerelease: false + generateReleaseNotes: true \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 506f81160..9f6756451 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- feat(cli): launcher script and release workflows - fix: cleaned cli settings for sequencer, devnet and full - feat: move to karnot runner - fix: docker file fixes for devnet diff --git a/Dockerfile b/Dockerfile index 1a2ba9ab2..d75185f7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,18 +17,21 @@ COPY crates crates COPY cairo cairo COPY cairo_0 cairo_0 -# Installing scarb, new since devnet integration -# Installation steps are taken from the scarb build script -# https://github.com/software-mansion/scarb/blob/main/install.sh -ENV SCARB_VERSION="v2.8.2" -ENV SCARB_REPO="https://github.com/software-mansion/scarb/releases/download" -ENV PLATFORM="x86_64-unknown-linux-gnu" -ENV SCARB_TARGET="/usr/src/scarb.tar.gz" - -RUN curl -fLS -o $SCARB_TARGET \ - $SCARB_REPO/$SCARB_VERSION/scarb-$SCARB_VERSION-$PLATFORM.tar.gz && \ - tar -xz -C /usr/src/ --strip-components=1 -f $SCARB_TARGET && \ - mv /usr/src/bin/scarb /bin +# Installing Scarb +# Dynamically detect the architecture +ARG SCARB_VERSION="v2.8.2" +ARG SCARB_REPO="https://github.com/software-mansion/scarb/releases/download" +RUN ARCH=$(uname -m); \ + if [ "$ARCH" = "x86_64" ]; then \ + PLATFORM="x86_64-unknown-linux-gnu"; \ + elif [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then \ + PLATFORM="aarch64-unknown-linux-gnu"; \ + else \ + echo "Unsupported architecture: $ARCH"; exit 1; \ + fi && \ + curl -fLS -o /usr/src/scarb.tar.gz \ + $SCARB_REPO/$SCARB_VERSION/scarb-$SCARB_VERSION-$PLATFORM.tar.gz && \ + tar -xz -C /usr/local --strip-components=1 -f /usr/src/scarb.tar.gz # Build the application in release mode RUN cargo build --release @@ -49,7 +52,7 @@ WORKDIR /usr/local/bin # Copy the compiled binary from the builder stage COPY --from=builder /usr/src/madara/target/release/madara . -# chain presets to be monted at startup +# Chain presets to be mounted at startup VOLUME crates/primitives/chain_config/presets VOLUME crates/primitives/chain_config/resources diff --git a/scripts/launcher b/scripts/launcher index c0286472e..a2cc388a1 100755 --- a/scripts/launcher +++ b/scripts/launcher @@ -40,7 +40,7 @@ case "$OS" in *) echo "Unsupported OS: $OS"; exit 1;; esac -# Couleurs et styles +# Colors and styles GREEN=$(tput setaf 2) YELLOW=$(tput setaf 3) RED=$(tput setaf 1) @@ -50,11 +50,11 @@ BOLD=$(tput bold) UNDERLINE=$(tput smul) BLINK=$(tput blink) -# IcΓ΄nes ASCII pour les liens sociaux +# Icons for social links GITHUB_ICON="πŸ”— GitHub: " DOCS_ICON="πŸ“„ Documentation: " -# Fonction pour la barre de progression +# Function for progress bar progress_bar() { local duration=${1} already_done() { for ((done=0; done<$elapsed; done++)); do printf "β–‡"; done } @@ -73,22 +73,29 @@ progress_bar() { # ASCII Art ascii_art() { echo -e "${RED} - ____ - / __ \___ ____ _ ____ _______ - / / / / _ \/ __ \| |/_/ / / / ___/ - / /_/ / __/ /_/ /> /dev/null 2>&1 } +# Function to check if Docker is installed +check_docker_installed() { + if ! command -v docker >/dev/null 2>&1; then + return 1 + else + return 0 + fi +} + +# Function to check if Docker daemon is running +check_docker_running() { + if ! docker info >/dev/null 2>&1; then + return 1 + else + return 0 + fi +} + # Check dependencies MISSING_DEPS=() for DEP in "${DEPENDENCIES[@]}"; do @@ -145,112 +153,160 @@ for DEP in "${DEPENDENCIES[@]}"; do fi done +# Check for Docker +DOCKER_MISSING=false +DOCKER_NOT_RUNNING=false + +if ! check_docker_installed; then + DOCKER_MISSING=true +elif ! check_docker_running; then + DOCKER_NOT_RUNNING=true +fi + # Report missing dependencies -if [ ${#MISSING_DEPS[@]} -ne 0 ]; then - echo -e "${YELLOW}The following dependencies are missing:${NC}" +if [ ${#MISSING_DEPS[@]} -ne 0 ] || [ "$DOCKER_MISSING" = true ]; then + echo -e "${YELLOW}\nThe following dependencies are missing or not running:${NC}" for DEP in "${MISSING_DEPS[@]}"; do echo -e "${YELLOW}- $DEP${NC}" done - + if [ "$DOCKER_MISSING" = true ]; then + echo -e "${YELLOW}- Docker${NC}" + fi + echo -e "\n${YELLOW}${BOLD}Do you want to install the missing dependencies? (yes/no)${NC}" read -p "> " INSTALL_DEPS - + if [ "$INSTALL_DEPS" != "yes" ]; then echo -e "\n${RED}Installation aborted.${NC}" exit 1 else echo -e "\n${GREEN}Installing missing dependencies...${NC}" if [ "$OS" == "Linux" ]; then - sudo apt update - for DEP in "${MISSING_DEPS[@]}"; do - if ! sudo apt install -y "$DEP"; then - echo -e "${RED}Failed to install $DEP.${NC}" - STILL_MISSING_DEPS+=("$DEP") - fi - done + sudo apt update + for DEP in "${MISSING_DEPS[@]}"; do + if [ "$DEP" == "yq" ]; then + echo -e "${GREEN}Installing yq...${NC}" + sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/local/bin/yq + sudo chmod +x /usr/local/bin/yq + continue + fi + if ! sudo apt install -y "$DEP"; then + echo -e "${RED}Failed to install $DEP.${NC}" + fi + done + if [ "$DOCKER_MISSING" = true ]; then + echo -e "${GREEN}Installing Docker...${NC}" + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + rm get-docker.sh + sudo usermod -aG docker $USER + newgrp docker + sudo systemctl start docker + fi elif [ "$OS" == "Mac" ]; then - for DEP in "${MISSING_DEPS[@]}"; do - if ! brew install "$DEP"; then - echo -e "${RED}Failed to install $DEP.${NC}" - STILL_MISSING_DEPS+=("$DEP") - fi - done + for DEP in "${MISSING_DEPS[@]}"; do + if [ "$DEP" == "yq" ]; then + echo -e "${GREEN}Installing yq via Homebrew...${NC}" + if ! brew install yq; then + echo -e "${RED}Failed to install yq.${NC}" + fi + continue + fi + if ! brew install "$DEP"; then + echo -e "${RED}Failed to install $DEP.${NC}" + fi + done + if [ "$DOCKER_MISSING" = true ]; then + echo -e "${GREEN}Installing Docker via Homebrew...${NC}" + if ! brew install --cask docker; then + echo -e "${RED}Failed to install Docker.${NC}" + else + echo -e "${GREEN}Docker installed.\nTrying to open /Applications/Docker.app to start the Docker daemon.${NC}" + open /Applications/Docker.app + # Wait for Docker daemon to start + echo -e "${GREEN}Waiting for Docker daemon to start...${NC}" + while ! docker info >/dev/null 2>&1; do + sleep 1 + done + echo -e "${GREEN}Docker daemon is running.${NC}" + fi + fi fi fi - - # Re-check dependencies to ensure all are installed - echo -e "\n${GREEN}Verifying installation of dependencies...${NC}" - RECHECK_MISSING_DEPS=() - for DEP in "${MISSING_DEPS[@]}"; do - DEP_CHECK="${DEPENDENCIES[@]#*:}" - if ! check_dependency "$DEP_CHECK"; then - RECHECK_MISSING_DEPS+=("$DEP") - fi - done +fi - if [ ${#RECHECK_MISSING_DEPS[@]} -ne 0 ]; then - echo -e "\n${RED}The following dependencies could not be installed:${NC}" - for DEP in "${RECHECK_MISSING_DEPS[@]}"; do - echo -e "${RED}- $DEP${NC}" +# Check if Docker daemon is running +if [ "$DOCKER_NOT_RUNNING" = true ]; then + echo -e "\n${YELLOW}Docker is installed but not running.${NC}" + if [ "$OS" == "Linux" ]; then + echo -e "${GREEN}Starting Docker daemon...${NC}" + sudo systemctl start docker + if ! sudo systemctl is-active --quiet docker; then + echo -e "${RED}Failed to start Docker daemon.${NC}" + exit 1 + else + echo -e "${GREEN}Docker daemon is running.${NC}" + fi + elif [ "$OS" == "Mac" ]; then + echo -e "${GREEN}Trying to open /Applications/Docker.app to start the Docker daemon.${NC}" + open /Applications/Docker.app + # Wait for Docker daemon to start + echo -e "${GREEN}Waiting for Docker daemon to start...${NC}" + while ! docker info >/dev/null 2>&1; do + sleep 1 done - exit 1 - else - echo -e "\n${GREEN}All dependencies are successfully installed and verified.${NC}" + echo -e "${GREEN}Docker daemon is running.${NC}" fi -else - echo -e "\n${GREEN}All dependencies are installed.${NC}" fi +# Re-check dependencies to ensure all are installed and running +echo -e "\n${GREEN}Verifying installation of dependencies...${NC}" +RECHECK_MISSING_DEPS=() +for DEP in "${DEPENDENCIES[@]}"; do + DEP_NAME="${DEP%%:*}" + DEP_CHECK="${DEP##*:}" + if ! check_dependency "$DEP_CHECK"; then + RECHECK_MISSING_DEPS+=("$DEP_NAME") + fi +done -echo -e "\n${GREEN}We will now proceed with the download and installation of the binary from GitHub:${NC}" -echo -e "${CYAN}${GITHUB_ICON}${UNDERLINE}https://github.com/madara-alliance/madara${NC}" - -echo -e "\n${YELLOW}${BOLD}Do you want to proceed? (yes/no)${NC}" -read -p "> " PROCEED - -tput rc -tput ed - -if [ "$PROCEED" != "yes" ]; then - echo -e "${RED}Operation aborted.${NC}" - exit 1 -fi - -# Function to check if a command exists -command_exists () { - type "$1" &> /dev/null ; -} - -# Check if curl is installed -if ! command_exists curl ; then - echo -e "${RED}Error: curl is not installed. Please install curl and try again.${NC}" - exit 1 -fi - -# Check if rustup is installed -if ! command_exists rustup ; then - echo -e "${YELLOW}Installing rustup...${NC}" - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - source $HOME/.cargo/env +# Re-check Docker +if ! check_docker_installed; then + RECHECK_MISSING_DEPS+=("Docker") +elif ! check_docker_running; then + RECHECK_MISSING_DEPS+=("Docker daemon not running") fi -# Check if cargo is installed -if ! command_exists cargo ; then - echo -e "${RED}Error: cargo is not installed. Please install Rust and try again.${NC}" +if [ ${#RECHECK_MISSING_DEPS[@]} -ne 0 ]; then + echo -e "\n${RED}The following dependencies could not be installed or are not running:${NC}" + for DEP in "${RECHECK_MISSING_DEPS[@]}"; do + echo -e "${RED}- $DEP${NC}" + done exit 1 +else + echo -e "\n${GREEN}All dependencies are successfully installed and verified.${NC}" fi -# Install the binary from a given URL -BIN_URL="https://example.com/path/to/your/binary" # Replace with actual URL -BIN_NAME="madara" # Replace with the actual name of the binary - -echo -e "\n${GREEN}Downloading the binary...${NC}" -curl -L $BIN_URL -o /usr/local/bin/$BIN_NAME -chmod +x /usr/local/bin/$BIN_NAME +# Choose the mode +echo -e "\nπŸ•ΉοΈ ${YELLOW}${BOLD}On which mode would you like to run Madara? (Enter a number)${NC}\n" +echo "${YELLOW}1. Full Node${NC}" +echo "${YELLOW}2. Sequencer${NC}" +echo "${YELLOW}3. Devnet${NC}" +while true; do + read -p "> " MODE_CHOICE + case $MODE_CHOICE in + 1) MODE="full"; break ;; + 2) MODE="sequencer"; break ;; + 3) MODE="devnet"; break ;; + *) echo -e "${YELLOW}Invalid choice, please enter 1, 2, or 3.${NC}" ;; + esac +done tput rc tput ed +echo -e "\n${GREEN}Madara will run in ${BOLD}${MODE}${NC}${GREEN} mode.${NC}" + # Ask for the node name while true; do echo -e "\n${YELLOW}${BOLD}πŸ‘€ What name would you like to give this node?${NC}" @@ -265,23 +321,7 @@ done tput rc tput ed -# Choose the network -echo -e "\n🌐 ${YELLOW}${BOLD}On which network? (Enter a number)${NC}\n" -echo "${YELLOW}1. Mainnet${NC}" -echo "${YELLOW}2. Testnet${NC}" -echo "${YELLOW}3. Integration${NC}" -while true; do - read -p "> " NETWORK_CHOICE - case $NETWORK_CHOICE in - 1) NETWORK="main"; break ;; - 2) NETWORK="test"; break ;; - 3) NETWORK="integration"; break ;; - *) echo -e "${YELLOW}Invalid choice, please enter 1, 2, or 3.${NC}" ;; - esac -done - -tput rc -tput ed +echo -e "\n${GREEN}Your node has been correctly named: ${BOLD}${NODE_NAME}${NC}${GREEN}.${NC}" # Ask for the database path echo -e "\nπŸ’Ύ ${YELLOW}${BOLD}Where would you like to store your database? (default: /tmp/madara)${NC}" @@ -291,6 +331,212 @@ BASE_PATH=${BASE_PATH:-/tmp/madara} tput rc tput ed +# Create the base path directory if it doesn't exist +if [ ! -d "$BASE_PATH" ]; then + mkdir -p "$BASE_PATH" +fi + +# Modify Chain Config Function +modify_chain_config() { + local config_file="$1" + local OVERRIDES_FILE="$BASE_PATH/overrides.txt" + > "$OVERRIDES_FILE" # Empty the overrides file + + # Read all leaf nodes with their paths and values + config_entries=() + while IFS= read -r line; do + config_entries+=("$line") + done < <(yq eval '.. | select(tag != "!!map" and tag != "!!seq") | [path | join("."), .] | @tsv' "$config_file") + + tput rc + tput ed + + # Display all parameters with improved formatting + echo -e "\n${YELLOW}${BOLD}Here are all the parameters of your chosen configuration:${NC}\n" + + prev_prefix="" + for i in "${!config_entries[@]}"; do + entry="${config_entries[$i]}" + path=$(echo "$entry" | cut -f1) + value=$(echo "$entry" | cut -f2-) + + # Extract the top-level prefix for grouping + prefix=$(echo "$path" | cut -d'.' -f1) + + # Add a new line and header when a new group starts + if [[ "$prefix" != "$prev_prefix" ]]; then + echo -e "${BLUE}${BOLD}$prefix:${NC}" + prev_prefix="$prefix" + fi + + # Indent sub-parameters + sub_path=$(echo "$path" | cut -d'.' -f2-) + if [[ -n "$sub_path" ]]; then + display_path=" - ${sub_path}" + else + display_path=" - $prefix" + fi + + echo -e "${YELLOW}$((i+1)). ${display_path} = ${value}${NC}" + done + + # Ask user which parameters to modify + echo -e "\n${YELLOW}Enter the numbers of the parameters you wish to modify, separated by spaces (e.g., 1 3 5).${NC}" + echo -e "${YELLOW}Press Enter to continue without modifying any parameters.${NC}" + read -p "> " MODIFY_NUMBERS + + # Check if the user wants to skip modifications + if [[ -z "$MODIFY_NUMBERS" ]]; then + echo -e "${GREEN}No parameters selected for modification. Proceeding with the original configuration.${NC}" + else + selected_indices=($MODIFY_NUMBERS) + + for index in "${selected_indices[@]}"; do + # Subtract 1 to convert to zero-based index + idx=$((index - 1)) + if [ "$idx" -ge 0 ] && [ "$idx" -lt "${#config_entries[@]}" ]; then + entry="${config_entries[$idx]}" + path=$(echo "$entry" | cut -f1) + value=$(echo "$entry" | cut -f2-) + echo -e "\n${YELLOW}Parameter: ${path}${NC}" + echo -e "${GREEN}Current value: ${value}${NC}" + echo -e "${YELLOW}Enter new value for ${path}:${NC}" + read -p "> " NEW_VALUE + echo "${path}=${NEW_VALUE}" >> "$OVERRIDES_FILE" + else + echo -e "${RED}Invalid selection: $index${NC}" + fi + done + fi + + # Apply the overrides to the original config file and write to $BASE_PATH/chain_config.yaml + MODIFIED_CONFIG_PATH="$BASE_PATH/chain_config.yaml" + cp "$config_file" "$MODIFIED_CONFIG_PATH" + + if [[ -s "$OVERRIDES_FILE" ]]; then + while IFS= read -r line; do + key=$(echo "$line" | cut -d'=' -f1) + val=$(echo "$line" | cut -d'=' -f2-) + yq eval -i ".${key} = \"${val}\"" "$MODIFIED_CONFIG_PATH" + done < "$OVERRIDES_FILE" + fi + + # Set CHAIN_CONFIG_FILE to the path of the modified chain config + CHAIN_CONFIG_FILE="$MODIFIED_CONFIG_PATH" +} + +# Choose the network based on the mode +if [ "$MODE" == "sequencer" ] || [ "$MODE" == "devnet" ]; then + # For sequencer and devnet modes + echo -e "\n🌐 ${YELLOW}${BOLD}Please choose one of the available presets or provide a custom chain config path: (Enter a number)${NC}\n" + echo "${YELLOW}1. Starknet Mainnet${NC}" + echo "${YELLOW}2. Starknet Testnet${NC}" + echo "${YELLOW}3. Devnet${NC}" + echo "${YELLOW}4. Custom Chain config${NC}" + while true; do + read -p "> " NETWORK_CHOICE + case $NETWORK_CHOICE in + 1) + PRESET="starknet_mainnet" + PRESET_URL="${PRESET_URLS[$PRESET]}" + ;; + 2) + PRESET="starknet_testnet" + PRESET_URL="${PRESET_URLS[$PRESET]}" + ;; + 3) + PRESET="devnet" + PRESET_URL="${PRESET_URLS[$PRESET]}" + ;; + 4) + echo -e "\n${YELLOW}Please provide the path to your custom chain config:${NC}" + read -p "> " CUSTOM_CHAIN_CONFIG + if [ -f "$CUSTOM_CHAIN_CONFIG" ]; then + PRESET="custom" + PRESET_PATH="$CUSTOM_CHAIN_CONFIG" + else + echo -e "${RED}File not found. Please provide a valid path.${NC}" + continue + fi + ;; + *) echo -e "${YELLOW}Invalid choice, please enter 1, 2, 3, or 4.${NC}"; continue ;; + esac + + # Now, if a preset was selected (options 1-3), download the chain config file + if [ "$PRESET" != "custom" ]; then + # Download the chain config file to a temporary location + PRESET_PATH=$(mktemp) + curl -s -o "$PRESET_PATH" "$PRESET_URL" + if [ $? -ne 0 ] || [ ! -s "$PRESET_PATH" ]; then + echo -e "${RED}Failed to download the chain config file from $PRESET_URL.${NC}" + exit 1 + fi + fi + + # Call modify_chain_config with the chain config file + modify_chain_config "$PRESET_PATH" + break + done +else + # For full node mode + echo -e "\n🌐 ${YELLOW}${BOLD}Please choose a Network or provide a custom Chain config path: (Enter a number)${NC}\n" + echo "${YELLOW}1. Starknet Mainnet${NC}" + echo "${YELLOW}2. Starknet Testnet${NC}" + echo "${YELLOW}3. Test${NC}" + echo "${YELLOW}4. Custom Chain config${NC}" + while true; do + read -p "> " NETWORK_CHOICE + case $NETWORK_CHOICE in + 1) + NETWORK="main" + PRESET="starknet_mainnet" + PRESET_URL="${PRESET_URLS[$PRESET]}" + ;; + 2) + NETWORK="test" + PRESET="starknet_testnet" + PRESET_URL="${PRESET_URLS[$PRESET]}" + ;; + 3) + NETWORK="test" + PRESET="test" + PRESET_URL="${PRESET_URLS[$PRESET]}" + ;; + 4) + echo -e "\n${YELLOW}Please provide the path to your custom chain config:${NC}" + read -p "> " CUSTOM_CHAIN_CONFIG + if [ -f "$CUSTOM_CHAIN_CONFIG" ]; then + NETWORK="custom" + PRESET_PATH="$CUSTOM_CHAIN_CONFIG" + else + echo -e "${RED}File not found. Please provide a valid path.${NC}" + continue + fi + ;; + *) echo -e "${YELLOW}Invalid choice, please enter 1, 2, 3, or 4.${NC}"; continue ;; + esac + + # For options 1-3, download the chain config file and call modify_chain_config + if [ "$NETWORK" != "custom" ]; then + PRESET_PATH=$(mktemp) + curl -s -o "$PRESET_PATH" "$PRESET_URL" + if [ $? -ne 0 ] || [ ! -s "$PRESET_PATH" ]; then + echo -e "${RED}Failed to download the chain config file from $PRESET_URL.${NC}" + exit 1 + fi + fi + + # Call modify_chain_config with the chain config file + modify_chain_config "$PRESET_PATH" + break + done +fi + +tput rc +tput ed + +echo -e "\n${GREEN}You have chosen to run your node under the preset or custom chain config.${NC}" + # Ask for RPC access while true; do echo -e "\nπŸ”Œ ${YELLOW}${BOLD}Do you want to enable RPC access? (yes/no) ${NC}" @@ -306,12 +552,32 @@ tput ed if [ "$RPC_ACCESS" == "yes" ]; then RPC_OPTS="--rpc-cors '*' --rpc-external" - echo -e "\nπŸšͺ ${YELLOW}${BOLD}On which port do you want RPC access? (default: 9933)${NC}" - read -p "> " RPC_PORT - RPC_PORT=${RPC_PORT:-9933} + echo -e "\nπŸšͺ ${YELLOW}${BOLD}On which port do you want RPC access? (default: 9944)${NC}" + + while true; do + read -p "> " RPC_PORT + RPC_PORT=${RPC_PORT:-9944} + + # Check if the port is a valid number between 1 and 65535 + if ! [[ "$RPC_PORT" =~ ^[0-9]+$ ]] || [ "$RPC_PORT" -lt 1 ] || [ "$RPC_PORT" -gt 65535 ]; then + echo -e "${RED}⚠️ Invalid port number. Please enter a valid port between 1 and 65535.${NC}" + continue + fi + + # Check if the port is already in use + if lsof -i :"$RPC_PORT" &>/dev/null; then + echo -e "${RED}⚠️ Port $RPC_PORT is already in use. Please choose another port.${NC}" + continue + fi + + break + done + RPC_OPTS="$RPC_OPTS --rpc-port $RPC_PORT" + PORT_MAPPING="-p $RPC_PORT:$RPC_PORT" else RPC_OPTS="" + PORT_MAPPING="" fi tput rc @@ -319,7 +585,7 @@ tput ed # Ask for the L1 endpoint URL while true; do - echo -e "\nπŸ”— ${YELLOW}${BOLD}Enter the URL of the L1 endpoint:${NC}" + echo -e "\nπŸ”— ${YELLOW}${BOLD}Provide an L1 RPC endpoint (URL format):${NC}" read -p "> " L1_ENDPOINT if [[ $L1_ENDPOINT =~ ^https?:// ]]; then break @@ -331,34 +597,66 @@ done tput rc tput ed -# Synchronize via snapshot or genesis -echo -e "\nπŸ”„ ${YELLOW}${BOLD}Which sync mode would you like? (Enter a number)${NC}\n" -echo "${YELLOW}1. Snap sync (fast)${NC}" -echo "${YELLOW}2. Full sync (safe)${NC}" -while true; do - read -p "> " SYNC_CHOICE - case $SYNC_CHOICE in - 1) SYNC_OPT="--snap"; break ;; - 2) SYNC_OPT=""; break ;; - *) echo -e "${YELLOW}Invalid choice, please enter 1 or 2.${NC}" ;; - esac -done - -tput rc -tput ed +# Check if the image is available locally +IMAGE_NAME="ghcr.io/madara-alliance/madara/madara:latest" +if docker images --format "{{.Repository}}:{{.Tag}}" | grep -q "$IMAGE_NAME"; then + echo -e "\nπŸ“¦ ${GREEN}Docker image '$IMAGE_NAME' is already available locally.${NC}" +else + echo -e "\n🚒 ${YELLOW}${BOLD}Docker image not found locally. Pulling from GitHub Packages...${NC}" + docker pull $IMAGE_NAME +fi -# Build the final command -COMMAND="/usr/local/bin/$BIN_NAME run --name $NODE_NAME --network=$NETWORK --base-path=$BASE_PATH $RPC_OPTS --l1-endpoint $L1_ENDPOINT $SYNC_OPT" +# Build the final Docker run command +DOCKER_COMMAND="docker run -d --name madara-client \ + -v ${BASE_PATH}:/data \ + ${PORT_MAPPING} \ + $IMAGE_NAME \ + --${MODE} --name \"${NODE_NAME}\" --chain-config=\"/data/chain_config.yaml\" --base-path=\"/data\" ${RPC_OPTS} --l1-endpoint \"${L1_ENDPOINT}\"" -echo -e "\nπŸ”„ ${YELLOW}${BOLD}The following command will be executed:${NC}\n" -echo -e "${CYAN}$COMMAND${NC}" +echo -e "\nπŸ”„ ${YELLOW}${BOLD}The following Docker command will be executed:${NC}\n" +echo -e "${CYAN}$DOCKER_COMMAND${NC}" # Confirm before executing echo -e "\n${YELLOW}${BOLD}Do you want to proceed? (yes/no)${NC}\n" read -p "> " CONFIRM if [ "$CONFIRM" == "yes" ]; then - echo -e "\n${GREEN}Starting the node...${NC}" - eval $COMMAND + echo -e "\n${GREEN}Starting the Madara node via Docker...${NC}" + # Stop and remove any existing container with the same name + if docker ps -a --format '{{.Names}}' | grep -Eq "^madara-client\$"; then + echo -e "\n${YELLOW}A container named 'madara-client' already exists. Stopping and removing it...${NC}" + docker stop madara-client + docker rm madara-client + fi + eval $DOCKER_COMMAND + tput rc + tput ed + # Check if the Madara Docker container is running + if docker ps --format '{{.Names}}' | grep -q '^madara-client$'; then + echo -e "\n${GREEN}Madara client is running.${NC}" + echo -e "${YELLOW}Container details:${NC}" + docker inspect madara-client --format ' + Name: {{.Name}} + ID: {{.Id}} + Image: {{.Config.Image}} + Status: {{.State.Status}} + StartedAt: {{.State.StartedAt}} + Ports: {{range $p, $conf := .NetworkSettings.Ports}}{{$p}}: {{(index $conf 0).HostPort}}{{end}}' + + echo -e "\n${YELLOW}Client Logs (last 10 lines):${NC}" + docker logs --tail 10 madara-client + + # Ask the user whether to quit or display more logs + echo -e "\n${YELLOW}${BOLD}Would you like to display the full logs of the running instance or quit? (logs/quit)${NC}\n" + read -p "> " USER_CHOICE + if [ "$USER_CHOICE" == "logs" ]; then + echo -e "\n${YELLOW}Displaying full logs...${NC}" + docker logs -f madara-client + else + echo -e "\n${GREEN}Exiting...${NC}" + fi + else + echo -e "${RED}Madara client is not running.${NC}" + fi else echo -e "${RED}Command execution aborted.${NC}" -fi +fi \ No newline at end of file