/ devnet / scripts / stop.sh
stop.sh
  1  #!/usr/bin/env bash
  2  #
  3  # stop.sh - Stop the ADnet development network
  4  #
  5  # Usage: ./stop.sh [OPTIONS]
  6  #
  7  # Options:
  8  #   -d, --data-dir DIR     Data directory (default: .devnet)
  9  #   --save-state           Save state before stopping
 10  #   -f, --force            Force kill processes
 11  #   -v, --verbose          Enable verbose output
 12  #   -h, --help             Show this help message
 13  
 14  set -euo pipefail
 15  
 16  # Script directory
 17  SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
 18  DEVNET_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
 19  
 20  # Default configuration
 21  DATA_DIR="${DEVNET_DIR}/.devnet"
 22  SAVE_STATE=false
 23  FORCE=false
 24  VERBOSE=false
 25  
 26  # Colors for output
 27  RED='\033[0;31m'
 28  GREEN='\033[0;32m'
 29  YELLOW='\033[1;33m'
 30  BLUE='\033[0;34m'
 31  NC='\033[0m' # No Color
 32  
 33  # Logging functions
 34  log_info() {
 35      echo -e "${GREEN}[INFO]${NC} $1"
 36  }
 37  
 38  log_warn() {
 39      echo -e "${YELLOW}[WARN]${NC} $1"
 40  }
 41  
 42  log_error() {
 43      echo -e "${RED}[ERROR]${NC} $1" >&2
 44  }
 45  
 46  log_debug() {
 47      if [ "$VERBOSE" = true ]; then
 48          echo -e "${BLUE}[DEBUG]${NC} $1"
 49      fi
 50  }
 51  
 52  # Show usage
 53  usage() {
 54      cat <<EOF
 55  Usage: $(basename "$0") [OPTIONS]
 56  
 57  Stop the ADnet development network.
 58  
 59  Options:
 60      -d, --data-dir DIR     Data directory (default: .devnet)
 61      --save-state           Save state before stopping (placeholder)
 62      -f, --force            Force kill processes (SIGKILL)
 63      -v, --verbose          Enable verbose output
 64      -h, --help             Show this help message
 65  
 66  Examples:
 67      $(basename "$0")                    # Graceful stop
 68      $(basename "$0") -f                 # Force stop
 69      $(basename "$0") --save-state       # Save state before stopping
 70  
 71  EOF
 72      exit 0
 73  }
 74  
 75  # Parse command line arguments
 76  parse_args() {
 77      while [[ $# -gt 0 ]]; do
 78          case $1 in
 79              -d|--data-dir)
 80                  DATA_DIR="$2"
 81                  shift 2
 82                  ;;
 83              --save-state)
 84                  SAVE_STATE=true
 85                  shift
 86                  ;;
 87              -f|--force)
 88                  FORCE=true
 89                  shift
 90                  ;;
 91              -v|--verbose)
 92                  VERBOSE=true
 93                  shift
 94                  ;;
 95              -h|--help)
 96                  usage
 97                  ;;
 98              *)
 99                  log_error "Unknown option: $1"
100                  usage
101                  ;;
102          esac
103      done
104  }
105  
106  # Save state (placeholder)
107  save_state() {
108      if [ "$SAVE_STATE" = true ]; then
109          log_info "Saving state... (placeholder)"
110          # Future: Implement state snapshot
111      fi
112  }
113  
114  # Stop a process by PID file
115  stop_process() {
116      local pid_file=$1
117      local name=$2
118  
119      if [ ! -f "$pid_file" ]; then
120          log_debug "No PID file for $name"
121          return 0
122      fi
123  
124      local pid
125      pid=$(cat "$pid_file" 2>/dev/null || echo "")
126  
127      if [ -z "$pid" ]; then
128          log_debug "Empty PID file for $name"
129          rm -f "$pid_file"
130          return 0
131      fi
132  
133      if ! kill -0 "$pid" 2>/dev/null; then
134          log_debug "$name (PID $pid) not running"
135          rm -f "$pid_file"
136          return 0
137      fi
138  
139      log_info "Stopping $name (PID $pid)..."
140  
141      if [ "$FORCE" = true ]; then
142          kill -9 "$pid" 2>/dev/null || true
143      else
144          # Graceful shutdown
145          kill -TERM "$pid" 2>/dev/null || true
146  
147          # Wait for process to stop
148          local wait_count=0
149          while kill -0 "$pid" 2>/dev/null && [ $wait_count -lt 30 ]; do
150              sleep 0.5
151              wait_count=$((wait_count + 1))
152          done
153  
154          # Force kill if still running
155          if kill -0 "$pid" 2>/dev/null; then
156              log_warn "$name did not stop gracefully, forcing..."
157              kill -9 "$pid" 2>/dev/null || true
158          fi
159      fi
160  
161      rm -f "$pid_file"
162      log_debug "$name stopped"
163  }
164  
165  # Stop all validators
166  stop_validators() {
167      local pids_dir="${DATA_DIR}/pids"
168  
169      if [ ! -d "$pids_dir" ]; then
170          log_info "No PID directory found. Devnet may not be running."
171          return 0
172      fi
173  
174      # Find all validator PID files
175      local stopped=0
176      for pid_file in "$pids_dir"/validator-*.pid; do
177          if [ -f "$pid_file" ]; then
178              local name
179              name=$(basename "$pid_file" .pid)
180              stop_process "$pid_file" "$name"
181              stopped=$((stopped + 1))
182          fi
183      done
184  
185      if [ $stopped -eq 0 ]; then
186          log_info "No validators were running"
187      else
188          log_info "Stopped $stopped validator(s)"
189      fi
190  }
191  
192  # Verify all processes stopped
193  verify_stopped() {
194      local pids_dir="${DATA_DIR}/pids"
195  
196      if [ ! -d "$pids_dir" ]; then
197          return 0
198      fi
199  
200      local running=0
201      for pid_file in "$pids_dir"/*.pid; do
202          if [ -f "$pid_file" ]; then
203              local pid
204              pid=$(cat "$pid_file" 2>/dev/null || echo "")
205              if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
206                  running=$((running + 1))
207                  log_warn "Process $pid is still running"
208              fi
209          fi
210      done
211  
212      if [ $running -gt 0 ]; then
213          log_error "$running process(es) still running"
214          return 1
215      fi
216  
217      log_info "All processes stopped successfully"
218  }
219  
220  # Main function
221  main() {
222      parse_args "$@"
223  
224      echo ""
225      echo "Stopping ADnet Devnet..."
226      echo ""
227  
228      # Save state if requested
229      save_state
230  
231      # Stop all validators
232      stop_validators
233  
234      # Verify stopped
235      verify_stopped
236  
237      echo ""
238      echo "=========================================="
239      echo "  ADnet Devnet Stopped"
240      echo "=========================================="
241      echo ""
242  }
243  
244  # Run main
245  main "$@"