├── README.md ├── nock-install-mac.sh └── nock-install.sh /README.md: -------------------------------------------------------------------------------- 1 | # 配置要求 2 | 最低要求 64 G RAM 没有到这个要求的可以省省了。。。 3 | 4 | ## 一键命令 Linux 版 5 | ```bash 6 | wget -O nock-install.sh https://raw.githubusercontent.com/GzGod/nock/refs/heads/main/nock-install.sh && sed -i 's/\r$//' nock-install.sh && chmod +x nock-install.sh && ./nock-install.sh 7 | ``` 8 | ## 一键命令 Mac 版 9 | ```bash 10 | wget -O nock-install-mac.sh https://raw.githubusercontent.com/GzGod/nock/refs/heads/main/nock-install-mac.sh && sed -i 's/\r$//' nock-install-mac.sh && chmod +x nock-install-mac.sh && ./nock-install-mac.sh 11 | ``` 12 | 其中生成钱包这一步会生成 wallet.txt 相关内容看图 13 | image 14 | 15 | image 16 | 17 | ![image](https://github.com/user-attachments/assets/ad4c8b07-841b-412a-94b8-62556aa07cb0) 18 | 19 | -------------------------------------------------------------------------------- /nock-install-mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ========= 色彩定义 ========= 4 | RESET='\033[0m' 5 | BOLD='\033[1m' 6 | GREEN='\033[0;32m' 7 | BLUE='\033[0;34m' 8 | YELLOW='\033[1;33m' 9 | RED='\033[0;31m' 10 | 11 | # ========= 项目路径 ========= 12 | NCK_DIR="$HOME/nockchain" 13 | 14 | # ========= 横幅与署名 ========= 15 | function show_banner() { 16 | clear 17 | echo -e "${BOLD}${BLUE}" 18 | echo " ╔═╗╔═╦╗─╔╦═══╦═══╦═══╦═══╗" 19 | echo " ╚╗╚╝╔╣║─║║╔══╣╔═╗║╔═╗║╔═╗║" 20 | echo " ─╚╗╔╝║║─║║╚══╣║─╚╣║─║║║─║║" 21 | echo " ─╔╝╚╗║║─║║╔══╣║╔═╣╚═╝║║─║║" 22 | echo " ╔╝╔╗╚╣╚═╝║╚══╣╚╩═║╔═╗║╚═╝║" 23 | echo " ╚═╝╚═╩═══╩═══╩═══╩╝─╚╩═══╝" 24 | echo -e "${RESET}" 25 | echo " 关注TG频道:t.me/xuegaoz" 26 | echo " 我的GitHub:github.com/Gzgod" 27 | echo " 我的推特:推特雪糕战神@Xuegaogx" 28 | echo "-----------------------------------------------" 29 | echo "" 30 | } 31 | 32 | # ========= 等待任意键继续 ========= 33 | function pause_and_return() { 34 | echo "" 35 | read -n1 -r -p "按任意键返回主菜单..." key 36 | main_menu 37 | } 38 | 39 | # ========= 安装系统依赖 ========= 40 | function install_dependencies() { 41 | echo -e "[*] 检查 Homebrew..." 42 | if ! command -v brew &> /dev/null; then 43 | echo -e "${RED}[-] Homebrew 未安装,正在安装...${RESET}" 44 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 45 | # 配置 Homebrew 环境变量 46 | echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> "$HOME/.zshrc" 47 | eval "$(/opt/homebrew/bin/brew shellenv)" 48 | fi 49 | echo -e "[*] 更新 Homebrew 并安装依赖..." 50 | brew update && brew upgrade 51 | brew install curl git wget lz4 jq make gcc nano tmux htop llvm pkg-config openssl@3 leveldb tar clang ncdu unzip gnu-sed screen || { 52 | echo -e "${RED}[-] 依赖安装失败,请检查 Homebrew 或网络!${RESET}" 53 | pause_and_return 54 | return 55 | } 56 | echo -e "${GREEN}[+] 依赖安装完成。${RESET}" 57 | pause_and_return 58 | } 59 | 60 | # ========= 安装 Rust ========= 61 | function install_rust() { 62 | if command -v rustc &> /dev/null; then 63 | echo -e "${YELLOW}[!] Rust 已安装,跳过安装。${RESET}" 64 | pause_and_return 65 | return 66 | fi 67 | echo -e "[*] 安装 Rust..." 68 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 69 | source "$HOME/.cargo/env" || { echo -e "${RED}[-] 无法配置 Rust 环境变量!${RESET}"; pause_and_return; return; } 70 | rustup default stable 71 | echo -e "${GREEN}[+] Rust 安装完成。${RESET}" 72 | pause_and_return 73 | } 74 | 75 | # ========= 设置仓库 ========= 76 | function setup_repository() { 77 | echo -e "[*] 检查 nockchain 仓库..." 78 | if [ -d "$NCK_DIR" ]; then 79 | echo -e "${YELLOW}[?] 已存在 nockchain 目录,是否删除重新克隆?(y/n)${RESET}" 80 | read -r confirm 81 | if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then 82 | rm -rf "$NCK_DIR" "$HOME/.nockapp" 83 | git clone https://github.com/zorp-corp/nockchain "$NCK_DIR" 84 | else 85 | cd "$NCK_DIR" && git pull 86 | fi 87 | else 88 | git clone https://github.com/zorp-corp/nockchain "$NCK_DIR" 89 | fi 90 | if [ $? -ne 0 ]; then 91 | echo -e "${RED}[-] 克隆仓库失败,请检查网络或权限!${RESET}" 92 | pause_and_return 93 | return 94 | fi 95 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 96 | if [ -f ".env" ]; then 97 | cp .env .env.bak 98 | echo -e "[*] .env 已备份为 .env.bak" 99 | fi 100 | if [ -f ".env_example" ]; then 101 | cp .env_example .env 102 | echo -e "${GREEN}[+] 环境文件 .env 已创建。${RESET}" 103 | else 104 | echo -e "${RED}[-] 未找到 .env_example 文件,请检查仓库!${RESET}" 105 | fi 106 | echo -e "${GREEN}[+] 仓库设置完成。${RESET}" 107 | pause_and_return 108 | } 109 | 110 | # ========= 编译项目和配置环境变量 ========= 111 | function build_and_configure() { 112 | if [ ! -d "$NCK_DIR" ]; then 113 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3 设置仓库!${RESET}" 114 | pause_and_return 115 | return 116 | fi 117 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 118 | echo -e "[*] 编译核心组件..." 119 | make install-hoonc || { echo -e "${RED}[-] 执行 make install-hoonc 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 120 | if command -v hoonc &> /dev/null; then 121 | echo -e "[*] hoonc 安装成功,可用命令:hoonc" 122 | else 123 | echo -e "${YELLOW}[!] 警告:hoonc 命令不可用,安装可能不完整。${RESET}" 124 | fi 125 | make build || { echo -e "${RED}[-] 执行 make build 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 126 | make install-nockchain-wallet || { echo -e "${RED}[-] 执行 make install-nockchain-wallet 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 127 | make install-nockchain || { echo -e "${RED}[-] 执行 make install-nockchain 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 128 | echo -e "[*] 配置环境变量..." 129 | RC_FILE="$HOME/.zshrc" 130 | if ! grep -q "$NCK_DIR/target/release" "$RC_FILE"; then 131 | echo "export PATH=\"\$PATH:$NCK_DIR/target/release\"" >> "$RC_FILE" 132 | source "$RC_FILE" || echo -e "${YELLOW}[!] 无法立即应用环境变量,请手动 source $RC_FILE 或重新打开终端。${RESET}" 133 | else 134 | source "$RC_FILE" || echo -e "${YELLOW}[!] 无法立即应用环境变量,请手动 source $RC_FILE 或重新打开终端。${RESET}" 135 | fi 136 | echo -e "${GREEN}[+] 编译和环境变量配置完成。${RESET}" 137 | pause_and_return 138 | } 139 | 140 | # ========= 生成钱包 ========= 141 | function generate_wallet() { 142 | if [ ! -d "$NCK_DIR" ] || [ ! -f "$NCK_DIR/target/release/nockchain-wallet" ]; then 143 | echo -e "${RED}[-] 未找到钱包命令或 nockchain 目录,请先运行选项 3 和 4!${RESET}" 144 | pause_and_return 145 | return 146 | fi 147 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 148 | echo -e "[*] 生成钱包密钥对..." 149 | read -p "[?] 是否创建钱包?[Y/n]: " create_wallet 150 | create_wallet=${create_wallet:-y} 151 | if [[ ! "$create_wallet" =~ ^[Yy]$ ]]; then 152 | echo -e "[*] 已跳过钱包创建。" 153 | pause_and_return 154 | return 155 | fi 156 | if ! command -v nockchain-wallet &> /dev/null; then 157 | echo -e "${RED}[-] nockchain-wallet 命令不可用,请检查 target/release 目录或构建过程!${RESET}" 158 | pause_and_return 159 | return 160 | fi 161 | nockchain-wallet keygen > wallet_keys.txt 2>&1 || { echo -e "${RED}[-] nockchain-wallet keygen 执行失败!${RESET}"; pause_and_return; return; } 162 | echo -e "${GREEN}[+] 钱包密钥已保存到 $NCK_DIR/wallet_keys.txt,请妥善保管!${RESET}" 163 | PUBLIC_KEY=$(grep -i "public key" wallet_keys.txt | awk '{print $NF}' | tail -1) 164 | if [ -n "$PUBLIC_KEY" ]; then 165 | echo -e "${YELLOW}公钥:${RESET}\n$PUBLIC_KEY" 166 | echo -e "${YELLOW}[!] 请使用选项 6 设置挖矿公钥或手动将以下公钥添加到 $NCK_DIR/.env 文件中:${RESET}" 167 | echo -e "MINING_PUBKEY=$PUBLIC_KEY" 168 | else 169 | echo -e "${RED}[-] 无法提取公钥,请检查 wallet_keys.txt!${RESET}" 170 | fi 171 | echo -e "${GREEN}[+] 钱包生成完成。${RESET}" 172 | pause_and_return 173 | } 174 | 175 | # ========= 设置挖矿公钥 ========= 176 | function configure_mining_key() { 177 | if [ ! -d "$NCK_DIR" ]; then 178 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 179 | pause_and_return 180 | return 181 | fi 182 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 183 | echo -e "[*] 设置挖矿公钥(MINING_PUBKEY)..." 184 | read -p "[?] 请输入您的 MINING_PUBKEY(可从选项 5 获取): " public_key 185 | if [ -z "$public_key" ]; then 186 | echo -e "${RED}[-] 未提供 MINING_PUBKEY,请输入有效的公钥!${RESET}" 187 | pause_and_return 188 | return 189 | fi 190 | if [ ! -f ".env" ]; then 191 | echo -e "${RED}[-] .env 文件不存在,请先运行选项 3 设置仓库!${RESET}" 192 | pause_and_return 193 | return 194 | fi 195 | if ! grep -q "^MINING_PUBKEY=" .env; then 196 | echo "MINING_PUBKEY=$public_key" >> .env 197 | else 198 | gsed -i "s|^MINING_PUBKEY=.*|MINING_PUBKEY=$public_key|" .env || { 199 | echo -e "${RED}[-] 无法更新 .env 文件中的 MINING_PUBKEY!${RESET}" 200 | pause_and_return 201 | return 202 | } 203 | fi 204 | if grep -q "^MINING_PUBKEY=$public_key$" .env; then 205 | echo -e "${GREEN}[+] .env 文件中的 MINING_PUBKEY 更新成功!${RESET}" 206 | else 207 | echo -e "${RED}[-] .env 文件更新失败,请检查文件内容!${RESET}" 208 | fi 209 | echo -e "${GREEN}[+] 挖矿公钥设置完成。${RESET}" 210 | pause_and_return 211 | } 212 | 213 | # ========= 启动 Miner 节点 ========= 214 | function start_miner_node() { 215 | if [ ! -d "$NCK_DIR" ]; then 216 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 217 | pause_and_return 218 | return 219 | fi 220 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 221 | 222 | # 验证 nockchain 命令是否可用 223 | echo -e "[*] 正在验证 nockchain 命令..." 224 | if ! command -v nockchain &> /dev/null; then 225 | echo -e "${RED}[-] nockchain 命令不可用,请检查选项 4 是否成功!${RESET}" 226 | echo -e "${YELLOW}[!] 请确保 \$PATH 包含 $NCK_DIR/target/release,可运行 'source ~/.zshrc' 或重新打开终端${RESET}" 227 | pause_and_return 228 | return 229 | fi 230 | 231 | # 验证 screen 和 tee 命令是否可用 232 | echo -e "[*] 正在验证 screen 和 tee 命令..." 233 | if ! command -v screen &> /dev/null; then 234 | echo -e "${RED}[-] screen 命令不可用,请确保已安装 screen(运行选项 1 或手动安装)!${RESET}" 235 | pause_and_return 236 | return 237 | fi 238 | if ! command -v tee &> /dev/null; then 239 | echo -e "${RED}[-] tee 命令不可用,请确保已安装 tee!${RESET}" 240 | pause_and_return 241 | return 242 | fi 243 | 244 | # 从 .env 文件中读取公钥 245 | if [ -f ".env" ]; then 246 | public_key=$(grep "^MINING_PUBKEY=" .env | cut -d'=' -f2) 247 | if [ -z "$public_key" ]; then 248 | echo -e "${YELLOW}[!] .env 文件中未找到 MINING_PUBKEY,请使用选项 6 设置或手动输入。${RESET}" 249 | read -p "[?] 请输入您的 MINING_PUBKEY(可从选项 5 获取): " public_key 250 | if [ -z "$public_key" ]; then 251 | echo -e "${RED}[-] 未提供 MINING_PUBKEY,请输入有效的公钥!${RESET}" 252 | pause_and_return 253 | return 254 | fi 255 | else 256 | echo -e "[*] 使用 .env 文件中的 MINING_PUBKEY:$public_key" 257 | fi 258 | else 259 | echo -e "${YELLOW}[!] .env 文件不存在,请使用选项 6 设置或手动输入 MINING_PUBKEY。${RESET}" 260 | read -p "[?] 请输入您的 MINING_PUBKEY(可从选项 5 获取): " public_key 261 | if [ -z "$public_key" ]; then 262 | echo -e "${RED}[-] 未提供 MINING_PUBKEY,请输入有效的公钥!${RESET}" 263 | pause_and_return 264 | return 265 | fi 266 | fi 267 | 268 | # 提示清理数据目录 269 | if [ -d ".data.nockchain" ]; then 270 | echo -e "${YELLOW}[?] 检测到数据目录 .data.nockchain,是否清理以重新初始化?(y/n)${RESET}" 271 | read -r confirm_clean 272 | if [[ "$confirm_clean" == "y" || "$confirm_clean" == "Y" ]]; then 273 | echo -e "[*] 备份并清理数据目录..." 274 | mv .data.nockchain .data.nockchain.bak-$(date +%F-%H%M%S) 2>/dev/null 275 | echo -e "${GREEN}[+] 数据目录已清理,备份至 .data.nockchain.bak-*${RESET}" 276 | fi 277 | fi 278 | 279 | # 默认端口 280 | LEADER_PORT=3005 281 | FOLLOWER_PORT=3006 282 | PORTS_TO_CHECK=("$LEADER_PORT" "$FOLLOWER_PORT") 283 | PORTS_OCCUPIED=false 284 | declare -A PID_PORT_MAP 285 | 286 | # 检查端口占用(优先使用 lsof) 287 | echo -e "[*] 检查端口 $LEADER_PORT 和 $FOLLOWER_PORT 是否被占用..." 288 | if command -v lsof &> /dev/null; then 289 | for PORT in "${PORTS_TO_CHECK[@]}"; do 290 | PIDS=$(lsof -i :$PORT -t | sort -u) 291 | if [ -n "$PIDS" ]; then 292 | echo -e "${YELLOW}[!] 端口 $PORT 已被占用。${RESET}" 293 | for PID in $PIDS; do 294 | echo -e "${YELLOW}[!] 占用端口 $PORT 的进程 PID: $PID${RESET}" 295 | PID_PORT_MAP[$PID]+="$PORT " 296 | PORTS_OCCUPIED=true 297 | done 298 | fi 299 | done 300 | else 301 | echo -e "${RED}[-] 未找到 lsof 命令,无法检查端口!请安装 lsof(运行选项 1 或手动安装)。${RESET}" 302 | pause_and_return 303 | return 304 | fi 305 | 306 | # 处理端口占用 307 | if [ "$PORTS_OCCUPIED" = true ]; then 308 | echo -e "${YELLOW}[?] 检测到端口被占用,是否杀死占用进程以释放端口?(y/n)${RESET}" 309 | read -r confirm_kill 310 | if [[ "$confirm_kill" == "y" || "$confirm_kill" == "Y" ]]; then 311 | for PID in "${!PID_PORT_MAP[@]}"; do 312 | PORTS=${PID_PORT_MAP[$PID]} 313 | echo -e "[*] 正在杀死占用端口 $PORTS 的进程 (PID: $PID)..." 314 | kill -9 "$PID" 2>/dev/null 315 | if [ $? -eq 0 ]; then 316 | echo -e "${GREEN}[+] 成功杀死 PID $PID,端口 $PORTS 应已释放。${RESET}" 317 | else 318 | echo -e "${RED}[-] 无法杀死 PID $PID,请手动检查!${RESET}" 319 | pause_and_return 320 | return 321 | fi 322 | done 323 | echo -e "[*] 验证端口是否已释放..." 324 | for PORT in "${PORTS_TO_CHECK[@]}"; do 325 | if lsof -i :$PORT -t >/dev/null 2>&1; then 326 | echo -e "${RED}[-] 端口 $PORT 仍被占用,请手动检查!${RESET}" 327 | pause_and_return 328 | return 329 | fi 330 | done 331 | else 332 | echo -e "${RED}[-] 用户取消杀死进程,无法启动 Miner 节点!${RESET}" 333 | pause_and_return 334 | return 335 | fi 336 | else 337 | echo -e "${GREEN}[+] 端口 $LEADER_PORT 和 $FOLLOWER_PORT 未被占用。${RESET}" 338 | fi 339 | 340 | # 清理现有的 miner screen 会话 341 | echo -e "[*] 正在清理现有的 miner screen 会话..." 342 | screen -ls | grep -q "miner" && screen -X -S miner quit 343 | 344 | # 启动 Miner 节点,使用公钥和 peer 参数 345 | echo -e "[*] 正在启动 Miner 节点..." 346 | NOCKCHAIN_CMD="RUST_LOG=trace ./target/release/nockchain --mining-pubkey \"$public_key\" --mine --peer /ip4/95.216.102.60/udp/3006/quic-v1 --peer /ip4/65.108.123.225/udp/3006/quic-v1 --peer /ip4/65.109.156.108/udp/3006/quic-v1 --peer /ip4/65.21.67.175/udp/3006/quic-v1 --peer /ip4/65.109.156.172/udp/3006/quic-v1 --peer /ip4/34.174.22.166/udp/3006/quic-v1 --peer /ip4/34.95.155.151/udp/30000/quic-v1 --peer /ip4/34.18.98.38/udp/30000/quic-v1" 347 | 348 | echo -e "${GREEN}[+] 启动 nockchain 节点在 screen 会话 'miner' 中,日志同时输出到 $NCK_DIR/miner.log${RESET}" 349 | echo -e "${YELLOW}[!] 使用 'screen -r miner' 查看节点实时输出,Ctrl+A 然后 D 脱离 screen(节点继续运行)${RESET}" 350 | screen -dmS miner -L -Logfile "$NCK_DIR/screen_miner.log" bash -c "source $HOME/.zshrc; $NOCKCHAIN_CMD 2>&1 | tee -a miner.log; echo 'nockchain 已退出,查看日志:$NCK_DIR/miner.log'; sleep 30" 351 | 352 | sleep 5 353 | if screen -ls | grep -q "miner"; then 354 | echo -e "${GREEN}[+] Miner 节点已在 screen 会话 'miner' 中运行,可使用 'screen -r miner' 查看${RESET}" 355 | echo -e "${GREEN}[+] 所有步骤已成功完成!${RESET}" 356 | echo -e "当前目录:$(pwd)" 357 | echo -e "MINING_PUBKEY 已设置为:$public_key" 358 | echo -e "Leader 端口:$LEADER_PORT" 359 | echo -e "Follower 端口:$FOLLOWER_PORT" 360 | if [ -f "wallet_keys.txt" ]; then 361 | echo -e "钱包密钥已生成,保存在 $NCK_DIR/wallet_keys.txt,请妥善保存!" 362 | fi 363 | if [ -f "miner.log" ] && [ -s "miner.log" ]; then 364 | echo -e "${YELLOW}[!] miner.log 内容:${RESET}" 365 | tail -n 10 miner.log 366 | else 367 | echo -e "${YELLOW}[!] miner.log 文件尚未生成或为空,请稍后检查或使用 'screen -r miner' 查看实时输出${RESET}" 368 | fi 369 | if [ -f "$NCK_DIR/screen_miner.log" ] && [ -s "$NCK_DIR/screen_miner.log" ]; then 370 | echo -e "${YELLOW}[!] screen_miner.log 内容(最后 10 行):${RESET}" 371 | tail -n 10 "$NCK_DIR/screen_miner.log" 372 | else 373 | echo -e "${YELLOW}[!] screen_miner.log 文件尚未生成或为空,可能是 screen 输出问题${RESET}" 374 | fi 375 | else 376 | echo -e "${RED}[-] 无法启动 Miner 节点!请检查 $NCK_DIR/miner.log 和 $NCK_DIR/screen_miner.log${RESET}" 377 | echo -e "${YELLOW}[!] 最后 10 行 miner.log:${RESET}" 378 | tail -n 10 "$NCK_DIR/miner.log" 2>/dev/null || echo -e "${YELLOW}[!] 未找到 miner.log${RESET}" 379 | echo -e "${YELLOW}[!] 最后 10 行 screen_miner.log:${RESET}" 380 | tail -n 10 "$NCK_DIR/screen_miner.log" 2>/dev/null || echo -e "${YELLOW}[!] 未找到 screen_miner.log${RESET}" 381 | fi 382 | pause_and_return 383 | } 384 | 385 | # ========= 备份密钥 ========= 386 | function backup_keys() { 387 | if [ ! -d "$NCK_DIR" ]; then 388 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 389 | pause_and_return 390 | return 391 | fi 392 | if ! command -v nockchain-wallet &> /dev/null; then 393 | echo -e "${RED}[-] nockchain-wallet 命令不可用,请先运行选项 4!${RESET}" 394 | pause_and_return 395 | return 396 | fi 397 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 398 | echo -e "[*] 备份密钥..." 399 | nockchain-wallet export-keys > nockchain_keys_backup.txt 2>&1 400 | if [ $? -eq 0 ]; then 401 | echo -e "${GREEN}[+] 密钥备份成功!已保存到 $NCK_DIR/nockchain_keys_backup.txt${RESET}" 402 | echo -e "${YELLOW}[!] 请妥善保管该文件,切勿泄露!${RESET}" 403 | else 404 | echo -e "${RED}[-] 密钥备份失败,请检查 nockchain-wallet export-keys 命令输出!${RESET}" 405 | echo -e "${YELLOW}[!] 详细信息见 $NCK_DIR/nockchain_keys_backup.txt${RESET}" 406 | fi 407 | pause_and_return 408 | } 409 | 410 | # ========= 查看节点日志 ========= 411 | function view_logs() { 412 | LOG_FILE="$NCK_DIR/miner.log" 413 | if [ -f "$LOG_FILE" ]; then 414 | echo -e "${GREEN}[+] 正在显示日志文件:$LOG_FILE${RESET}" 415 | tail -f "$LOG_FILE" 416 | else 417 | echo -e "${RED}[-] 日志文件 $LOG_FILE 不存在,请确认是否已运行选项 7 启动 Miner 节点!${RESET}" 418 | fi 419 | pause_and_return 420 | } 421 | 422 | # ========= 查询余额 ========= 423 | function check_balance() { 424 | if [ ! -d "$NCK_DIR" ]; then 425 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 426 | pause_and_return 427 | return 428 | fi 429 | if ! command -v nockchain-wallet &> /dev/null; then 430 | echo -e "${RED}[-] nockchain-wallet 命令不可用,请先运行选项 4!${RESET}" 431 | pause_and_return 432 | return 433 | fi 434 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 435 | 436 | # 检查 socket 文件(macOS 路径可能不同,需用户确认) 437 | SOCKET_PATH="$NCK_DIR/.socket/nockchain_npc.sock" 438 | if [ ! -S "$SOCKET_PATH" ]; then 439 | echo -e "${RED}[-] socket 文件 $SOCKET_PATH 不存在,请确保 nockchain 节点正在运行(可尝试选项 7)!${RESET}" 440 | echo -e "${YELLOW}[!] 如果 socket 路径不同,请手动查找(例如:find ~ -name nockchain_npc.sock)并更新脚本${RESET}" 441 | pause_and_return 442 | return 443 | fi 444 | 445 | # 执行余额查询 446 | echo -e "[*] 正在查询余额..." 447 | nockchain-wallet --nockchain-socket "$SOCKET_PATH" update-balance > balance_output.txt 2>&1 448 | if [ $? -eq 0 ]; then 449 | echo -e "${GREEN}[+] 余额查询成功!以下是查询结果:${RESET}" 450 | echo -e "----------------------------------------" 451 | cat balance_output.txt 452 | echo -e "----------------------------------------" 453 | else 454 | echo -e "${RED}[-] 余额查询失败,请检查 nockchain-wallet 命令或节点状态!${RESET}" 455 | echo -e "${YELLOW}[!] 详细信息见 $NCK_DIR/balance_output.txt${RESET}" 456 | fi 457 | pause_and_return 458 | } 459 | 460 | # ========= 主菜单 ========= 461 | function main_menu() { 462 | show_banner 463 | echo "请选择操作:" 464 | echo " 1) 安装系统依赖" 465 | echo " 2) 安装 Rust" 466 | echo " 3) 设置仓库" 467 | echo " 4) 编译项目和配置环境变量" 468 | echo " 5) 生成钱包" 469 | echo " 6) 设置挖矿公钥" 470 | echo " 7) 启动 Miner 节点" 471 | echo " 8) 备份密钥" 472 | echo " 9) 查看节点日志" 473 | echo " 10) 查询余额" 474 | echo " 0) 退出" 475 | echo "" 476 | read -p "请输入编号: " choice 477 | case "$choice" in 478 | 1) install_dependencies ;; 479 | 2) install_rust ;; 480 | 3) setup_repository ;; 481 | 4) build_and_configure ;; 482 | 5) generate_wallet ;; 483 | 6) configure_mining_key ;; 484 | 7) start_miner_node ;; 485 | 8) backup_keys ;; 486 | 9) view_logs ;; 487 | 10) check_balance ;; 488 | 0) echo -e "${GREEN}已退出。${RESET}"; exit 0 ;; 489 | *) echo -e "${RED}[-] 无效选项!${RESET}"; pause_and_return ;; 490 | esac 491 | } 492 | 493 | # ========= 启动主程序 ========= 494 | main_menu 495 | -------------------------------------------------------------------------------- /nock-install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ========= 色彩定义 ========= 4 | RESET='\033[0m' 5 | BOLD='\033[1m' 6 | GREEN='\033[0;32m' 7 | BLUE='\033[0;34m' 8 | YELLOW='\033[1;33m' 9 | RED='\033[0;31m' 10 | 11 | # ========= 项目路径 ========= 12 | NCK_DIR="$HOME/nockchain" 13 | 14 | # ========= 横幅与署名 ========= 15 | function show_banner() { 16 | clear 17 | echo -e "${BOLD}${BLUE}" 18 | echo " ╔═╗╔═╦╗─╔╦═══╦═══╦═══╦═══╗" 19 | echo " ╚╗╚╝╔╣║─║║╔══╣╔═╗║╔═╗║╔═╗║" 20 | echo " ─╚╗╔╝║║─║║╚══╣║─╚╣║─║║║─║║" 21 | echo " ─╔╝╚╗║║─║║╔══╣║╔═╣╚═╝║║─║║" 22 | echo " ╔╝╔╗╚╣╚═╝║╚══╣╚╩═║╔═╗║╚═╝║" 23 | echo " ╚═╝╚═╩═══╩═══╩═══╩╝─╚╩═══╝" 24 | echo -e "${RESET}" 25 | echo " 关注TG频道:t.me/xuegaoz" 26 | echo " 我的GitHub:github.com/Gzgod" 27 | echo " 我的推特:推特雪糕战神@Xuegaogx" 28 | echo "-----------------------------------------------" 29 | echo "" 30 | } 31 | 32 | # ========= 等待任意键继续 ========= 33 | function pause_and_return() { 34 | echo "" 35 | read -n1 -r -p "按任意键返回主菜单..." key 36 | main_menu 37 | } 38 | 39 | # ========= 安装系统依赖 ========= 40 | function install_dependencies() { 41 | if ! command -v apt-get &> /dev/null; then 42 | echo -e "${RED}[-] 此脚本假设使用 Debian/Ubuntu 系统 (apt)。请手动安装依赖!${RESET}" 43 | pause_and_return 44 | return 45 | fi 46 | echo -e "[*] 更新系统并安装依赖..." 47 | apt-get update && apt-get upgrade -y 48 | sudo apt install -y curl git make clang llvm-dev libclang-dev screen 49 | echo -e "${GREEN}[+] 依赖安装完成。${RESET}" 50 | pause_and_return 51 | } 52 | 53 | # ========= 安装 Rust ========= 54 | function install_rust() { 55 | if command -v rustc &> /dev/null; then 56 | echo -e "${YELLOW}[!] Rust 已安装,跳过安装。${RESET}" 57 | pause_and_return 58 | return 59 | fi 60 | echo -e "[*] 安装 Rust..." 61 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y 62 | source "$HOME/.cargo/env" || { echo -e "${RED}[-] 无法配置 Rust 环境变量!${RESET}"; pause_and_return; return; } 63 | rustup default stable 64 | echo -e "${GREEN}[+] Rust 安装完成。${RESET}" 65 | pause_and_return 66 | } 67 | 68 | # ========= 设置仓库 ========= 69 | function setup_repository() { 70 | echo -e "[*] 检查 nockchain 仓库..." 71 | if [ -d "$NCK_DIR" ]; then 72 | echo -e "${YELLOW}[?] 已存在 nockchain 目录,是否删除重新克隆?(y/n)${RESET}" 73 | read -r confirm 74 | if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then 75 | rm -rf "$NCK_DIR" "$HOME/.nockapp" 76 | git clone https://github.com/zorp-corp/nockchain "$NCK_DIR" 77 | else 78 | cd "$NCK_DIR" && git pull 79 | fi 80 | else 81 | git clone https://github.com/zorp-corp/nockchain "$NCK_DIR" 82 | fi 83 | if [ $? -ne 0 ]; then 84 | echo -e "${RED}[-] 克隆仓库失败,请检查网络或权限!${RESET}" 85 | pause_and_return 86 | return 87 | fi 88 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 89 | if [ -f ".env" ]; then 90 | cp .env .env.bak 91 | echo -e "[*] .env 已备份为 .env.bak" 92 | fi 93 | if [ -f ".env_example" ]; then 94 | cp .env_example .env 95 | echo -e "${GREEN}[+] 环境文件 .env 已创建。${RESET}" 96 | else 97 | echo -e "${RED}[-] 未找到 .env_example 文件,请检查仓库!${RESET}" 98 | fi 99 | echo -e "${GREEN}[+] 仓库设置完成。${RESET}" 100 | pause_and_return 101 | } 102 | 103 | # ========= 编译项目和配置环境变量 ========= 104 | function build_and_configure() { 105 | if [ ! -d "$NCK_DIR" ]; then 106 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3 设置仓库!${RESET}" 107 | pause_and_return 108 | return 109 | fi 110 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 111 | echo -e "[*] 编译核心组件..." 112 | make install-hoonc || { echo -e "${RED}[-] 执行 make install-hoonc 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 113 | if command -v hoonc &> /dev/null; then 114 | echo -e "[*] hoonc 安装成功,可用命令:hoonc" 115 | else 116 | echo -e "${YELLOW}[!] 警告:hoonc 命令不可用,安装可能不完整。${RESET}" 117 | fi 118 | make build || { echo -e "${RED}[-] 执行 make build 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 119 | make install-nockchain-wallet || { echo -e "${RED}[-] 执行 make install-nockchain-wallet 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 120 | make install-nockchain || { echo -e "${RED}[-] 执行 make install-nockchain 失败,请检查 Makefile 或依赖!${RESET}"; pause_and_return; return; } 121 | echo -e "[*] 配置环境变量..." 122 | RC_FILE="$HOME/.bashrc" 123 | [[ "$SHELL" == *"zsh"* ]] && RC_FILE="$HOME/.zshrc" 124 | if ! grep -q "$HOME/.cargo/bin" "$RC_FILE"; then 125 | echo "export PATH=\"\$PATH:$HOME/.cargo/bin\"" >> "$RC_FILE" 126 | source "$RC_FILE" || echo -e "${YELLOW}[!] 无法立即应用环境变量,请手动 source $RC_FILE 或重新打开终端。${RESET}" 127 | else 128 | source "$RC_FILE" || echo -e "${YELLOW}[!] 无法立即应用环境变量,请手动 source $RC_FILE 或重新打开终端。${RESET}" 129 | fi 130 | echo -e "${GREEN}[+] 编译和环境变量配置完成。${RESET}" 131 | pause_and_return 132 | } 133 | 134 | # ========= 生成钱包 ========= 135 | function generate_wallet() { 136 | if [ ! -d "$NCK_DIR" ] || [ ! -f "$NCK_DIR/target/release/nockchain-wallet" ]; then 137 | echo -e "${RED}[-] 未找到钱包命令或 nockchain 目录,请先运行选项 3 和 4!${RESET}" 138 | pause_and_return 139 | return 140 | fi 141 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 142 | echo -e "[*] 生成钱包密钥对..." 143 | read -p "[?] 是否创建钱包?[Y/n]: " create_wallet 144 | create_wallet=${create_wallet:-y} 145 | if [[ ! "$create_wallet" =~ ^[Yy]$ ]]; then 146 | echo -e "[*] 已跳过钱包创建。" 147 | pause_and_return 148 | return 149 | fi 150 | if ! command -v nockchain-wallet &> /dev/null; then 151 | echo -e "${RED}[-] nockchain-wallet 命令不可用,请检查 target/release 目录或构建过程!${RESET}" 152 | pause_and_return 153 | return 154 | fi 155 | nockchain-wallet keygen > wallet_keys.txt 2>&1 || { echo -e "${RED}[-] nockchain-wallet keygen 执行失败!${RESET}"; pause_and_return; return; } 156 | echo -e "${GREEN}[+] 钱包密钥已保存到 $NCK_DIR/wallet_keys.txt,请妥善保管!${RESET}" 157 | PUBLIC_KEY=$(grep -i "public key" wallet_keys.txt | awk '{print $NF}' | tail -1) 158 | if [ -n "$PUBLIC_KEY" ]; then 159 | echo -e "${YELLOW}公钥:${RESET}\n$PUBLIC_KEY" 160 | echo -e "${YELLOW}[!] 请使用选项 6 设置挖矿公钥或手动将以下公钥添加到 $NCK_DIR/.env 文件中:${RESET}" 161 | echo -e "MINING_PUBKEY=$PUBLIC_KEY" 162 | else 163 | echo -e "${RED}[-] 无法提取公钥,请检查 wallet_keys.txt!${RESET}" 164 | fi 165 | echo -e "${GREEN}[+] 钱包生成完成。${RESET}" 166 | pause_and_return 167 | } 168 | 169 | # ========= 设置挖矿公钥 ========= 170 | function configure_mining_key() { 171 | if [ ! -d "$NCK_DIR" ]; then 172 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 173 | pause_and_return 174 | return 175 | fi 176 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 177 | echo -e "[*] 设置挖矿公钥(MINING_PUBKEY)..." 178 | read -p "[?] 请输入您的 MINING_PUBKEY(可从选项 5 获取): " public_key 179 | if [ -z "$public_key" ]; then 180 | echo -e "${RED}[-] 未提供 MINING_PUBKEY,请输入有效的公钥!${RESET}" 181 | pause_and_return 182 | return 183 | fi 184 | if [ ! -f ".env" ]; then 185 | echo -e "${RED}[-] .env 文件不存在,请先运行选项 3 设置仓库!${RESET}" 186 | pause_and_return 187 | return 188 | fi 189 | if ! grep -q "^MINING_PUBKEY=" .env; then 190 | echo "MINING_PUBKEY=$public_key" >> .env 191 | else 192 | sed -i "s|^MINING_PUBKEY=.*|MINING_PUBKEY=$public_key|" .env || { 193 | echo -e "${RED}[-] 无法更新 .env 文件中的 MINING_PUBKEY!${RESET}" 194 | pause_and_return 195 | return 196 | } 197 | fi 198 | if grep -q "^MINING_PUBKEY=$public_key$" .env; then 199 | echo -e "${GREEN}[+] .env 文件中的 MINING_PUBKEY 更新成功!${RESET}" 200 | else 201 | echo -e "${RED}[-] .env 文件更新失败,请检查文件内容!${RESET}" 202 | fi 203 | echo -e "${GREEN}[+] 挖矿公钥设置完成。${RESET}" 204 | pause_and_return 205 | } 206 | 207 | # ========= 启动节点(Miner 或非 Miner) ========= 208 | function start_node() { 209 | if [ ! -d "$NCK_DIR" ]; then 210 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 211 | pause_and_return 212 | return 213 | fi 214 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 215 | 216 | # 验证 nockchain 命令是否可用 217 | echo -e "[*] 正在验证 nockchain 命令..." 218 | if ! command -v nockchain &> /dev/null; then 219 | echo -e "${RED}[-] nockchain 命令不可用,请检查选项 4 是否成功!${RESET}" 220 | echo -e "${YELLOW}[!] 请确保 \$PATH 包含 $HOME/.cargo/bin,可运行 'source ~/.bashrc' 或重新打开终端${RESET}" 221 | pause_and_return 222 | return 223 | fi 224 | 225 | # 验证 screen 命令是否可用 226 | echo -e "[*] 正在验证 screen 命令..." 227 | if ! command -v screen &> /dev/null; then 228 | echo -e "${RED}[-] screen 命令不可用,请确保已安装 screen(运行选项 1 或手动安装)!${RESET}" 229 | pause_and_return 230 | return 231 | fi 232 | 233 | # 选择节点类型 234 | echo -e "[*] 请选择节点类型:" 235 | echo -e " 1) Miner 节点(挖矿)" 236 | echo -e " 2) 非 Miner 节点(仅运行节点)" 237 | read -p "[?] 请输入编号 (1/2): " node_type 238 | if [[ "$node_type" != "1" && "$node_type" != "2" ]]; then 239 | echo -e "${RED}[-] 无效选项,请选择 1 或 2!${RESET}" 240 | pause_and_return 241 | return 242 | fi 243 | 244 | # 设置工作目录 245 | echo -e "[*] 输入节点工作目录(默认:$NCK_DIR)..." 246 | read -p "[?] 工作目录 [$NCK_DIR]: " work_dir 247 | work_dir=${work_dir:-$NCK_DIR} 248 | if [ ! -d "$work_dir" ]; then 249 | echo -e "[*] 创建工作目录 $work_dir..." 250 | mkdir -p "$work_dir" || { echo -e "${RED}[-] 无法创建工作目录!${RESET}"; pause_and_return; return; } 251 | cp "$NCK_DIR/.env" "$work_dir/.env" 2>/dev/null || echo -e "${YELLOW}[!] 未找到 .env 文件,请确保已运行选项 3!${RESET}" 252 | fi 253 | cd "$work_dir" || { echo -e "${RED}[-] 无法进入工作目录 $work_dir!${RESET}"; pause_and_return; return; } 254 | 255 | # 如果是 Miner 节点,获取公钥 256 | public_key="" 257 | if [ "$node_type" = "1" ]; then 258 | if [ -f ".env" ]; then 259 | public_key=$(grep "^MINING_PUBKEY=" .env | cut -d'=' -f2) 260 | if [ -z "$public_key" ]; then 261 | echo -e "${YELLOW}[!] .env 文件中未找到 MINING_PUBKEY,请使用选项 6 设置或手动输入。${RESET}" 262 | read -p "[?] 请输入您的 MINING_PUBKEY(可从选项 5 获取): " public_key 263 | if [ -z "$public_key" ]; then 264 | echo -e "${RED}[-] 未提供 MINING_PUBKEY,请输入有效的公钥!${RESET}" 265 | pause_and_return 266 | return 267 | fi 268 | else 269 | echo -e "[*] 使用 .env 文件中的 MINING_PUBKEY:$public_key" 270 | fi 271 | else 272 | echo -e "${YELLOW}[!] .env 文件不存在,请使用选项 6 设置或手动输入 MINING_PUBKEY。${RESET}" 273 | read -p "[?] 请输入您的 MINING_PUBKEY(可从选项 5 获取): " public_key 274 | if [ -z "$public_key" ]; then 275 | echo -e "${RED}[-] 未提供 MINING_PUBKEY,请输入有效的公钥!${RESET}" 276 | pause_and_return 277 | return 278 | fi 279 | fi 280 | fi 281 | 282 | # 提示清理数据目录 283 | if [ -d ".data.nockchain" ]; then 284 | echo -e "${YELLOW}[?] 检测到数据目录 .data.nockchain,是否清理以重新初始化?(y/n)${RESET}" 285 | read -r confirm_clean 286 | if [[ "$confirm_clean" == "y" || "$confirm_clean" == "Y" ]]; then 287 | echo -e "[*] 备份并清理数据目录..." 288 | mv .data.nockchain .data.nockchain.bak-$(date +%F-%H%M%S) 2>/dev/null 289 | echo -e "${GREEN}[+] 数据目录已清理,备份至 .data.nockchain.bak-*${RESET}" 290 | fi 291 | fi 292 | 293 | # 设置端口 294 | echo -e "[*] 输入节点端口(默认 Leader: 3005, Follower: 3006)..." 295 | read -p "[?] Leader 端口 [3005]: " LEADER_PORT 296 | LEADER_PORT=${LEADER_PORT:-3005} 297 | read -p "[?] Follower 端口 [3006]: " FOLLOWER_PORT 298 | FOLLOWER_PORT=${FOLLOWER_PORT:-3006} 299 | PORTS_TO_CHECK=("$LEADER_PORT" "$FOLLOWER_PORT") 300 | PORTS_OCCUPIED=false 301 | declare -A PID_PORT_MAP 302 | 303 | # 设置绑定地址 304 | echo -e "[*] 输入 P2P 绑定地址(例如 /ip4/0.0.0.0/udp/$FOLLOWER_PORT/quic-v1,若 NAT 后请输入公网 IP)..." 305 | read -p "[?] 绑定地址 [/ip4/0.0.0.0/udp/$FOLLOWER_PORT/quic-v1]: " bind_addr 306 | bind_addr=${bind_addr:-/ip4/0.0.0.0/udp/$FOLLOWER_PORT/quic-v1} 307 | 308 | # 检查端口占用 309 | echo -e "[*] 检查端口 $LEADER_PORT 和 $FOLLOWER_PORT 是否被占用..." 310 | if command -v lsof &> /dev/null; then 311 | for PORT in "${PORTS_TO_CHECK[@]}"; do 312 | PIDS=$(lsof -i :$PORT -t | sort -u) 313 | if [ -n "$PIDS" ]; then 314 | echo -e "${YELLOW}[!] 端口 $PORT 已被占用。${RESET}" 315 | for PID in $PIDS; do 316 | echo -e "${YELLOW}[!] 占用端口 $PORT 的进程 PID: $PID${RESET}" 317 | PID_PORT_MAP[$PID]+="$PORT " 318 | PORTS_OCCUPIED=true 319 | done 320 | fi 321 | done 322 | elif command -v netstat &> /dev/null; then 323 | for PORT in "${PORTS_TO_CHECK[@]}"; do 324 | PIDS=$(netstat -tulnp 2>/dev/null | grep ":$PORT " | awk '{print $7}' | cut -d'/' -f1 | sort -u) 325 | if [ -n "$PIDS" ]; then 326 | echo -e "${YELLOW}[!] 端口 $PORT 已被占用。${RESET}" 327 | for PID in $PIDS; do 328 | echo -e "${YELLOW}[!] 占用端口 $PORT 的进程 PID: $PID${RESET}" 329 | PID_PORT_MAP[$PID]+="$PORT " 330 | PORTS_OCCUPIED=true 331 | done 332 | fi 333 | done 334 | else 335 | echo -e "${RED}[-] 未找到 lsof 或 netstat 命令,无法检查端口!${RESET}" 336 | pause_and_return 337 | return 338 | fi 339 | 340 | # 处理端口占用 341 | if [ "$PORTS_OCCUPIED" = true ]; then 342 | echo -e "${YELLOW}[?] 检测到端口被占用,是否杀死占用进程以释放端口?(y/n)${RESET}" 343 | read -r confirm_kill 344 | if [[ "$confirm_kill" == "y" || "$confirm_kill" == "Y" ]]; then 345 | for PID in "${!PID_PORT_MAP[@]}"; do 346 | PORTS=${PID_PORT_MAP[$PID]} 347 | echo -e "[*] 正在杀死占用端口 $PORTS 的进程 (PID: $PID)..." 348 | if ! ps -p "$PID" -o user= | grep -q "^$USER$"; then 349 | echo -e "${YELLOW}[!] 进程 PID $PID 由其他用户拥有,尝试使用 sudo 杀死...${RESET}" 350 | sudo kill -9 "$PID" 2>/dev/null 351 | else 352 | kill -9 "$PID" 2>/dev/null 353 | fi 354 | if [ $? -eq 0 ]; then 355 | echo -e "${GREEN}[+] 成功杀死 PID $PID,端口 $PORTS 应已释放。${RESET}" 356 | else 357 | echo -e "${RED}[-] 无法杀死 PID $PID,请手动检查!${RESET}" 358 | pause_and_return 359 | return 360 | fi 361 | done 362 | echo -e "[*] 验证端口是否已释放..." 363 | for PORT in "${PORTS_TO_CHECK[@]}"; do 364 | if command -v lsof &> /dev/null && lsof -i :$PORT -t >/dev/null 2>&1; then 365 | echo -e "${RED}[-] 端口 $PORT 仍被占用,请手动检查!${RESET}" 366 | pause_and_return 367 | return 368 | elif command -v netstat &> /dev/null && netstat -tuln | grep -q ":$PORT "; then 369 | echo -e "${RED}[-] 端口 $PORT 仍被占用,请手动检查!${RESET}" 370 | pause_and_return 371 | return 372 | fi 373 | done 374 | else 375 | echo -e "${RED}[-] 用户取消杀死进程,无法启动节点!${RESET}" 376 | pause_and_return 377 | return 378 | fi 379 | else 380 | echo -e "${GREEN}[+] 端口 $LEADER_PORT 和 $FOLLOWER_PORT 未被占用。${RESET}" 381 | fi 382 | 383 | # 设置日志级别 384 | echo -e "[*] 请选择日志级别:" 385 | echo -e " 1) info(推荐,常规信息)" 386 | echo -e " 2) debug(调试信息)" 387 | echo -e " 3) trace(详细调试信息)" 388 | read -p "[?] 请输入编号 (1/2/3) [1]: " log_level_choice 389 | case "$log_level_choice" in 390 | 2) log_level="debug" ;; 391 | 3) log_level="trace" ;; 392 | *) log_level="info" ;; 393 | esac 394 | if [ -f ".env" ]; then 395 | if ! grep -q "^RUST_LOG=" .env; then 396 | echo "RUST_LOG=$log_level" >> .env 397 | else 398 | sed -i "s|^RUST_LOG=.*|RUST_LOG=$log_level|" .env 399 | fi 400 | fi 401 | echo -e "[*] 日志级别设置为:$log_level" 402 | 403 | # 询问是否输出 miner.log 404 | echo -e "${YELLOW}[?] 是否输出 miner.log 日志文件?(警告:日志文件可能占用较大磁盘空间,请谨慎选择!)[y/N]${RESET}" 405 | read -r log_to_file 406 | log_to_file=${log_to_file:-n} 407 | if [[ "$log_to_file" =~ ^[Yy]$ ]]; then 408 | echo -e "${GREEN}[+] 将输出日志到 $work_dir/miner.log,请定期清理以避免磁盘空间不足!${RESET}" 409 | log_output="2>&1 | tee -a miner.log" 410 | else 411 | echo -e "${YELLOW}[!] 已选择不输出 miner.log,日志仅保存在 screen 日志 $work_dir/screen_$session_name.log 中${RESET}" 412 | log_output="2>&1" 413 | fi 414 | 415 | # 清理现有的 screen 会话 416 | if [ "$node_type" = "1" ]; then 417 | session_name="miner" 418 | else 419 | session_name="node" 420 | fi 421 | echo -e "[*] 正在清理现有的 $session_name screen 会话..." 422 | screen -ls | grep -q "$session_name" && screen -X -S "$session_name" quit 423 | 424 | # 启动节点 425 | echo -e "[*] 正在启动节点..." 426 | if [ "$node_type" = "1" ]; then 427 | script="$NCK_DIR/scripts/run_nockchain_miner.sh" 428 | else 429 | script="$NCK_DIR/scripts/run_nockchain_node.sh" 430 | fi 431 | if [ ! -f "$script" ]; then 432 | echo -e "${RED}[-] 未找到 $script,请检查 nockchain 仓库!${RESET}" 433 | pause_and_return 434 | return 435 | fi 436 | chmod +x "$script" 437 | echo -e "${GREEN}[+] 启动节点在 screen 会话 '$session_name' 中,screen 日志输出到 $work_dir/screen_$session_name.log${RESET}" 438 | echo -e "${YELLOW}[!] 使用 'screen -r $session_name' 查看节点实时输出,Ctrl+A 然后 D 脱离 screen(节点继续运行)${RESET}" 439 | screen -dmS "$session_name" -L -Logfile "$work_dir/screen_$session_name.log" bash -c "source $HOME/.bashrc; sh $script --bind \"$bind_addr\" $log_output; echo '节点已退出,查看 screen 日志:$work_dir/screen_$session_name.log'; sleep 30" 440 | 441 | # 等待足够时间,确保 screen 会话初始化 442 | sleep 5 443 | 444 | # 检查 screen 会话是否运行 445 | if screen -ls | grep -q "$session_name"; then 446 | echo -e "${GREEN}[+] 节点已在 screen 会话 '$session_name' 中运行,可使用 'screen -r $session_name' 查看${RESET}" 447 | echo -e "${GREEN}[+] 所有步骤已成功完成!${RESET}" 448 | echo -e "工作目录:$work_dir" 449 | [ -n "$public_key" ] && echo -e "MINING_PUBKEY:$public_key" 450 | echo -e "Leader 端口:$LEADER_PORT" 451 | echo -e "Follower 端口:$FOLLOWER_PORT" 452 | echo -e "绑定地址:$bind_addr" 453 | if [ -f "wallet_keys.txt" ]; then 454 | echo -e "钱包密钥已生成,保存在 $work_dir/wallet_keys.txt,请妥善保存!" 455 | fi 456 | # 检查 miner.log 是否有内容(如果启用) 457 | if [[ "$log_to_file" =~ ^[Yy]$ ]] && [ -f "miner.log" ] && [ -s "miner.log" ]; then 458 | echo -e "${YELLOW}[!] miner.log 内容(最后 10 行):${RESET}" 459 | tail -n 10 miner.log 460 | elif [[ "$log_to_file" =~ ^[Yy]$ ]]; then 461 | echo -e "${YELLOW}[!] miner.log 文件尚未生成或为空,请稍后检查或使用 'screen -r $session_name' 查看实时输出${RESET}" 462 | fi 463 | # 检查 screen 日志 464 | if [ -f "$work_dir/screen_$session_name.log" ] && [ -s "$work_dir/screen_$session_name.log" ]; then 465 | echo -e "${YELLOW}[!] screen_$session_name.log 内容(最后 10 行):${RESET}" 466 | tail -n 10 "$work_dir/screen_$session_name.log" 467 | else 468 | echo -e "${YELLOW}[!] screen_$session_name.log 文件尚未生成或为空,可能是 screen 输出问题${RESET}" 469 | fi 470 | else 471 | echo -e "${RED}[-] 无法启动节点!请检查 $work_dir/screen_$session_name.log${RESET}" 472 | if [[ "$log_to_file" =~ ^[Yy]$ ]]; then 473 | echo -e "${YELLOW}[!] 最后 10 行 miner.log:${RESET}" 474 | tail -n 10 "$work_dir/miner.log" 2>/dev/null || echo -e "${YELLOW}[!] 未找到 miner.log${RESET}" 475 | fi 476 | echo -e "${YELLOW}[!] 最后 10 行 screen_$session_name.log:${RESET}" 477 | tail -n 10 "$work_dir/screen_$session_name.log" 2>/dev/null || echo -e "${YELLOW}[!] 未找到 screen_$session_name.log${RESET}" 478 | fi 479 | pause_and_return 480 | } 481 | 482 | # ========= 备份密钥 ========= 483 | function backup_keys() { 484 | if [ ! -d "$NCK_DIR" ]; then 485 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 486 | pause_and_return 487 | return 488 | fi 489 | if ! command -v nockchain-wallet &> /dev/null; then 490 | echo -e "${RED}[-] nockchain-wallet 命令不可用,请先运行选项 4!${RESET}" 491 | pause_and_return 492 | return 493 | fi 494 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 495 | echo -e "[*] 备份密钥..." 496 | nockchain-wallet export-keys > keys.export 2>&1 497 | if [ $? -eq 0 ]; then 498 | echo -e "${GREEN}[+] 密钥备份成功!已保存到 $NCK_DIR/keys.export${RESET}" 499 | echo -e "${YELLOW}[!] 请妥善保管该文件,切勿泄露!${RESET}" 500 | else 501 | echo -e "${RED}[-] 密钥备份失败,请检查 nockchain-wallet export-keys 命令输出!${RESET}" 502 | echo -e "${YELLOW}[!] 详细信息见 $NCK_DIR/keys.export${RESET}" 503 | fi 504 | pause_and_return 505 | } 506 | 507 | # ========= 查看节点日志 ========= 508 | function view_logs() { 509 | LOG_FILE="$NCK_DIR/miner.log" 510 | if [ -f "$LOG_FILE" ]; then 511 | echo -e "${GREEN}[+] 正在显示日志文件:$LOG_FILE${RESET}" 512 | tail -f "$LOG_FILE" 513 | else 514 | echo -e "${RED}[-] 日志文件 $LOG_FILE 不存在,请确认是否已运行选项 7 启动节点并启用 miner.log 输出!${RESET}" 515 | echo -e "${YELLOW}[!] 您可以检查 screen 日志 $NCK_DIR/screen_miner.log 或 $NCK_DIR/screen_node.log${RESET}" 516 | fi 517 | pause_and_return 518 | } 519 | 520 | # ========= 查询余额 ========= 521 | function check_balance() { 522 | if [ ! -d "$NCK_DIR" ]; then 523 | echo -e "${RED}[-] nockchain 目录不存在,请先运行选项 3!${RESET}" 524 | pause_and_return 525 | return 526 | fi 527 | if ! command -v nockchain-wallet &> /dev/null; then 528 | echo -e "${RED}[-] nockchain-wallet 命令不可用,请先运行选项 4!${RESET}" 529 | pause_and_return 530 | return 531 | fi 532 | cd "$NCK_DIR" || { echo -e "${RED}[-] 无法进入 nockchain 目录!${RESET}"; pause_and_return; return; } 533 | 534 | # 检查 socket 文件 535 | SOCKET_PATH="$NCK_DIR/nockchain.sock" 536 | if [ ! -S "$SOCKET_PATH" ]; then 537 | echo -e "${RED}[-] socket 文件 $SOCKET_PATH 不存在,请确保 nockchain 节点正在运行(可尝试选项 7)!${RESET}" 538 | pause_and_return 539 | return 540 | fi 541 | 542 | # 获取公钥 543 | public_key="" 544 | if [ -f ".env" ]; then 545 | public_key=$(grep "^MINING_PUBKEY=" .env | cut -d'=' -f2) 546 | fi 547 | 548 | # 执行余额查询 549 | echo -e "[*] 正在查询余额..." 550 | echo -e "${YELLOW}[!] 查询所有 UTXOs...${RESET}" 551 | nockchain-wallet --nockchain-socket "$SOCKET_PATH" list-notes > balance_output.txt 2>&1 552 | if [ $? -eq 0 ]; then 553 | echo -e "${GREEN}[+] 所有 UTXOs 查询成功!${RESET}" 554 | echo -e "----------------------------------------" 555 | cat balance_output.txt 556 | echo -e "----------------------------------------" 557 | else 558 | echo -e "${RED}[-] 所有 UTXOs 查询失败,请检查 nockchain-wallet 命令或节点状态!${RESET}" 559 | echo -e "${YELLOW}[!] 详细信息见 $NCK_DIR/balance_output.txt${RESET}" 560 | fi 561 | 562 | if [ -n "$public_key" ]; then 563 | echo -e "${YELLOW}[!] 查询公钥 $public_key 的 UTXOs...${RESET}" 564 | nockchain-wallet --nockchain-socket "$SOCKET_PATH" list-notes-by-pubkey "$public_key" > balance_output_pubkey.txt 2>&1 565 | if [ $? -eq 0 ]; then 566 | echo -e "${GREEN}[+] 公钥 UTXOs 查询成功!${RESET}" 567 | echo -e "----------------------------------------" 568 | cat balance_output_pubkey.txt 569 | echo -e "----------------------------------------" 570 | else 571 | echo -e "${RED}[-] 公钥 UTXOs 查询失败,请检查公钥或节点状态!${RESET}" 572 | echo -e "${YELLOW}[!] 详细信息见 $NCK_DIR/balance_output_pubkey.txt${RESET}" 573 | fi 574 | else 575 | echo -e "${YELLOW}[!] 未找到 MINING_PUBKEY,无法查询特定公钥的 UTXOs!${RESET}" 576 | fi 577 | pause_and_return 578 | } 579 | 580 | # ========= 主菜单 ========= 581 | function main_menu() { 582 | show_banner 583 | echo "请选择操作:" 584 | echo " 1) 安装系统依赖" 585 | echo " 2) 安装 Rust" 586 | echo " 3) 设置仓库" 587 | echo " 4) 编译项目和配置环境变量" 588 | echo " 5) 生成钱包" 589 | echo " 6) 设置挖矿公钥" 590 | echo " 7) 启动节点(Miner 或非 Miner)" 591 | echo " 8) 备份密钥" 592 | echo " 9) 查看节点日志" 593 | echo " 10) 查询余额" 594 | echo " 0) 退出" 595 | echo "" 596 | read -p "请输入编号: " choice 597 | case "$choice" in 598 | 1) install_dependencies ;; 599 | 2) install_rust ;; 600 | 3) setup_repository ;; 601 | 4) build_and_configure ;; 602 | 5) generate_wallet ;; 603 | 6) configure_mining_key ;; 604 | 7) start_node ;; 605 | 8) backup_keys ;; 606 | 9) view_logs ;; 607 | 10) check_balance ;; 608 | 0) echo -e "${GREEN}已退出。${RESET}"; exit 0 ;; 609 | *) echo -e "${RED}[-] 无效选项!${RESET}"; pause_and_return ;; 610 | esac 611 | } 612 | 613 | # ========= 启动主程序 ========= 614 | main_menu 615 | --------------------------------------------------------------------------------