github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/tools/deploy/network_on_multiple.sh (about) 1 #!/bin/bash 2 3 #set -x 4 5 start=$(date +%s) 6 7 rm -rf node* 8 9 if [ ! -e ./param_config.sh ];then 10 echo "Make sure the file ./param_config.sh exists" 11 exit 1 12 fi 13 source ./param_config.sh 14 15 cmd="./sipe" 16 17 if [ ! -f $cmd ];then 18 echo "Make sure the file $cmd exists" 19 exit 1 20 fi 21 22 chmod +x $cmd 23 24 if [ ! -f ./Permission.bin ];then 25 echo "Make sure the file ./Permission.bin exists" 26 exit 1 27 fi 28 29 # shellcheck disable=SC2154 30 allNodeCount=7 31 32 # shellcheck disable=SC2154 33 accountCount=${#accountPasswords[*]} 34 35 # shellcheck disable=SC2086 36 # shellcheck disable=SC2154 37 if [ $initNodeCount -gt $allNodeCount ];then 38 echo "The number of initial nodes is illegal. " 39 echo "The number of initial nodes must be less than or equal to the total number of nodes" 40 exit 1 41 fi 42 43 #一个节点一个账户,所以allNodeHosts的个数和ACCOUNT_PASSWORDS个数必须一致 44 # shellcheck disable=SC2086 45 if [ $allNodeCount != $accountCount ];then 46 echo "all node hosts must equal account password" 47 exit 1 48 fi 49 for((i=0;i<allNodeCount;i++)) 50 do 51 # shellcheck disable=SC2154 52 getConnection "${user}" "${allNodeHosts[$i]}" 53 done 54 55 echo "host check success" 56 57 ##同步时间 58 ## shellcheck disable=SC2004 59 #for((i=0;i<${allNodeCount};i++)) 60 #do 61 # scp ./check-system.sh "${user}@${allNodeHosts[$i]}:~/check-system.sh" 62 # ssh "${user}@${allNodeHosts[$i]}" "bash ~/check-system.sh" 63 #done 64 # 65 #echo "host time sync success" 66 # 67 ## shellcheck disable=SC2004 68 #for((i=0;i<$allNodeCount;i++)) 69 #do 70 # echo "host:${allNodeHosts[$i]}" 71 # ssh "${user}@${allNodeHosts[$i]}" "date" 72 #done 73 #echo "host time compare......" 74 75 accounts=() 76 77 encodeNodes=() 78 79 # shellcheck disable=SC2004 80 for((i=0;i<${allNodeCount};i++)) 81 do 82 mkdir -p "node-$i/data" 83 echo "${accountPasswords[$i]}">>"./node-$i/password.txt" 84 content=$($cmd --data.dir="./node-$i/data" --password="./node-$i/password.txt" account new) 85 echo "$content">>"./node-$i/data/content.txt" 86 temp="./node-$i/data/content.txt" 87 # shellcheck disable=SC2002 88 account=$(cat ${temp}| grep "Public address of the key"|awk -F":" '{print $2}'| awk '{print $1}') 89 accounts[$i]=$account 90 echo "$i account:$account" 91 rm -rf "./node-$i/data/content.txt" 92 done 93 94 95 genesis="{\"config\":{\"chainId\":" 96 97 # shellcheck disable=SC2154 98 genesis="$genesis$chainId," 99 100 # shellcheck disable=SC2154 101 genesis=$genesis"\"singularityBlock\": 0,\"hotstuff\": {\"view\": 0,\"council\": " 102 103 hotstuffpeer='[' 104 105 for((i=0;i<${allNodeCount};i++)) 106 do 107 peerInfo=$($cmd --data.dir=./node-$i/data genbls12sec) 108 # shellcheck disable=SC2086 109 if [ $i -eq $((allNodeCount-1)) ] ;then 110 hotstuffpeer=$hotstuffpeer"{\"id\":$((i+1)),\"publicKey\":\"0x$peerInfo\"}" 111 else 112 hotstuffpeer=$hotstuffpeer"{\"id\":$((i+1)),\"publicKey\":\"0x$peerInfo\"}," 113 fi 114 done 115 116 genesis=$genesis$hotstuffpeer"]}}, \"nonce\": \"0x0100000000000000\",\"timestamp\": \"0x611dd0cd\"," 117 118 extraData="\"0xc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"" 119 120 genesis=$genesis"\"extraData\":" 121 122 genesis=$genesis$extraData"," 123 124 # shellcheck disable=SC2154 125 genesis=$genesis"\"gasLimit\": \"$gasLimit\"," 126 127 end="\"difficulty\": \"0x1\",\"mixHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\",\"coinbase\": \"0x0000000000000000000000000000000000000000\"," 128 129 end=$end"\"alloc\": {\"0000000000000000000000000000000000000000\": {\"balance\": \"0x1\"}," 130 131 #根据初始化,给管理员也是出块账户分配余额 132 # shellcheck disable=SC2004 133 for((i=0;i<${initNodeCount};i++)) 134 do 135 # shellcheck disable=SC2086 136 if [ $i -eq $((initNodeCount-1)) ] ;then 137 # shellcheck disable=SC2154 138 end=$end"\"${accounts[$i]:2}\": {\"balance\": \"$balance\"}" 139 else 140 end=$end"\"${accounts[$i]:2}\": {\"balance\": \"$balance\"}," 141 fi 142 done 143 144 end=$end"}," 145 146 end=$end"\"number\": \"0x0\",\"gasUsed\": \"0x0\",\"parentHash\": \"0x0000000000000000000000000000000000000000000000000000000000000000\"}" 147 148 genesis=$genesis$end 149 150 #每个目录下的都拷贝一个genesis.json文件 151 # shellcheck disable=SC2004 152 for((i=0;i<${allNodeCount};i++)) 153 do 154 echo "$genesis">>"./node-$i/genesis.json" 155 done 156 157 # shellcheck disable=SC2046 158 # shellcheck disable=SC2164 159 workdir="$(cd $(dirname $0); pwd)" 160 161 localIP="127.0.0.1" 162 163 #初始化好每个节点目录 164 # shellcheck disable=SC2004 165 for((i=0;i<${allNodeCount};i++)) 166 do 167 # pkill sipe 168 169 #拷贝链的可执行程序 170 cp "$workdir/sipe" "$workdir/node-$i" 171 cp "$workdir/stop.sh" "$workdir/node-$i" 172 cp "$workdir/transaction_stat.sh" "$workdir/node-$i" 173 174 #进入节点对应的目录 175 # shellcheck disable=SC2164 176 cd "$workdir/node-$i" 177 178 #初始化链的数据目录 179 $cmd --data.dir=./data --no.usb init genesis.json 180 181 #将命令和启动参数都写入start.sh文件中 182 # shellcheck disable=SC2129 183 echo "#!/bin/bash">>./start.sh 184 echo "export dataDir=./data">>./start.sh 185 # shellcheck disable=SC2154 186 echo "export httpPort=$httpPort">>./start.sh 187 # shellcheck disable=SC2154 188 echo "export p2pPort=$p2pPort">>./start.sh 189 echo "export unlockAccount=${accounts[$i]}">>./start.sh 190 echo "export password=./password.txt">>./start.sh 191 # shellcheck disable=SC2154 192 echo "export WsPort=$websocketPort">>./start.sh 193 echo "nohup $cmd \\">>./start.sh 194 echo "--no.discover \\">>./start.sh 195 echo "--no.usb \\">>./start.sh 196 echo "--data.dir \$dataDir \\">>./start.sh 197 # echo "--gc.mode archive \\">>./start.sh 198 echo "--allow-insecure-unlock \\">>./start.sh 199 echo "--http \\">>./start.sh 200 echo "--http.addr '0.0.0.0' \\">>./start.sh 201 echo "--http.port \$httpPort \\">>./start.sh 202 echo "--http.api 'admin,miner,db,eth,net,web3,personal,debug,txpool,permission,raft,clique' \\">>./start.sh 203 echo "--http.cors.domain '*' \\">>./start.sh 204 echo "--port \$p2pPort \\">>./start.sh 205 echo "--tx.pool.global.slots 10000 \\">>./start.sh 206 echo "--mine \\">>./start.sh 207 echo "--miner.ether.base \$unlockAccount \\">>./start.sh 208 echo "--miner.gas.price 0 \\">>./start.sh 209 # shellcheck disable=SC2154 210 echo "--miner.gas.limit $gasLimitDecimal \\">>./start.sh 211 echo "--unlock \$unlockAccount \\">>./start.sh 212 echo "--password \$password \\">>./start.sh 213 echo "--ws \\">>./start.sh 214 echo "--ws.addr '0.0.0.0' \\">>./start.sh 215 echo "--ws.port \$WsPort \\">>./start.sh 216 echo "--ws.api 'admin,miner,db,eth,net,web3,personal,debug,txpool,permission,raft,clique' \\">>./start.sh 217 echo "--ws.origins '*' \\">>./start.sh 218 echo "--graphql \\">>./start.sh 219 echo "--graphql.addr '0.0.0.0' \\">>./start.sh 220 # shellcheck disable=SC2154 221 echo "--graphql.port $graphqlPort \\">>./start.sh 222 echo "--graphql.cors.domain '*' \\">>./start.sh 223 echo "--graphql.vhosts '*' \\">>./start.sh 224 echo "--miner.no.empty \\">>./start.sh 225 echo "--miner.recommit='15s' \\">>./start.sh 226 echo "--sync.mode full \\">>./start.sh 227 echo "--verbosity 4 \\">>./start.sh 228 echo "--permission \\">>./start.sh 229 echo "--hotstuff \\">>./start.sh 230 echo " >> app.log 2>&1 &">>./start.sh 231 232 # shellcheck disable=SC2129 233 echo "#!/bin/bash">>./start-with-ca.sh 234 echo "export dataDir=./data">>./start-with-ca.sh 235 echo "export httpPort=$httpPort">>./start-with-ca.sh 236 echo "export p2pPort=$p2pPort">>./start-with-ca.sh 237 echo "export unlockAccount=${accounts[$i]}">>./start-with-ca.sh 238 echo "export password=./password.txt">>./start-with-ca.sh 239 echo "export websocketPort=$websocketPort">>./start-with-ca.sh 240 echo "nohup $cmd \\">>./start-with-ca.sh 241 echo "--no.discover \\">>./start-with-ca.sh 242 echo "--no.usb \\">>./start-with-ca.sh 243 echo "--data.dir \$dataDir \\">>./start-with-ca.sh 244 echo "--gc.mode archive \\">>./start-with-ca.sh 245 echo "--allow-insecure-unlock \\">>./start-with-ca.sh 246 echo "--http \\">>./start-with-ca.sh 247 echo "--http.addr '0.0.0.0' \\">>./start-with-ca.sh 248 echo "--http.port \$httpPort \\">>./start-with-ca.sh 249 echo "--http.api 'admin,miner,db,eth,net,web3,personal,debug,txpool,permission,raft,clique' \\">>./start-with-ca.sh 250 echo "--http.cors.domain '*' \\">>./start-with-ca.sh 251 echo "--port \$p2pPort \\">>./start-with-ca.sh 252 echo "--tx.pool.global.slots 10000 \\">>./start-with-ca.sh 253 echo "--mine \\">>./start-with-ca.sh 254 echo "--miner.no.empty \\">>./start.sh 255 echo "--miner.ether.base \$unlockAccount \\">>./start-with-ca.sh 256 echo "--miner.gas.price 0 \\">>./start-with-ca.sh 257 echo "--miner.gas.limit $gasLimitDecimal \\">>./start-with-ca.sh 258 echo "--unlock \$unlockAccount \\">>./start-with-ca.sh 259 echo "--password \$password \\">>./start-with-ca.sh 260 echo "--sync.mode full \\">>./start-with-ca.sh 261 echo "--verbosity 4 \\">>./start-with-ca.sh 262 echo "--ws \\">>./start-with-ca.sh 263 echo "--ws.addr '0.0.0.0' \\">>./start-with-ca.sh 264 echo "--ws.port \$websocketPort \\">>./start-with-ca.sh 265 echo "--ws.api 'admin,miner,db,eth,net,web3,personal,debug,txpool,permission,raft,clique' \\">>./start-with-ca.sh 266 echo "--ws.origins '*' \\">>./start-with-ca.sh 267 echo "--peer.tls.enable \\">>./start-with-ca.sh 268 # shellcheck disable=SC2154 269 echo "--peer.tls.dir ${baseDir}/$projectDir/node-$i/node-$i/peer/tls-msp \\">>./start-with-ca.sh 270 echo "--api.tls.enable \\">>./start-with-ca.sh 271 echo "--graphql \\">>./start-with-ca.sh 272 echo "--graphql.addr '0.0.0.0' \\">>./start-with-ca.sh 273 echo "--graphql.port 8547 \\">>./start-with-ca.sh 274 echo "--graphql.cors.domain '*' \\">>./start-with-ca.sh 275 echo "--graphql.vhosts '*' \\">>./start-with-ca.sh 276 echo "--permission \\">>./start-with-ca.sh 277 echo "--hotstuff \\">>./start.sh 278 echo " >> app.log 2>&1 &">>./start.sh 279 280 #启动链服务 281 bash ./start.sh 282 # shellcheck disable=SC2154 283 sleep "$waitPeriod" 284 if [ ! -e "./data/sipe.ipc" ];then 285 ls ./data 286 sleep 5 287 fi 288 #获取节点的enode 289 encodeNode=$($cmd attach data/sipe.ipc --exec "admin.nodeInfo.enode") 290 291 ip=${allNodeHosts[$i]} 292 293 #将127.0.0.1替换为具体的ip地址 294 remote=${encodeNode//$localIP/$ip} 295 296 encodeNodes[(($i))]=$remote 297 298 bash ./stop.sh 299 300 done 301 302 #pkill sipe 303 304 len=${#encodeNodes[*]} 305 306 staticNodes='[' 307 308 for((i=0;i<len;i++)) 309 do 310 if [ $i -eq $((len-1)) ] ;then 311 staticNodes=$staticNodes${encodeNodes[$i]} 312 else 313 staticNodes=$staticNodes${encodeNodes[$i]}',' 314 fi 315 done 316 317 staticNodes=$staticNodes"]" 318 319 echo "staticNodes:$staticNodes" 320 321 # shellcheck disable=SC2164 322 cd "$workdir" 323 324 #每个目录下都有一个static-nodes.json文件 325 # shellcheck disable=SC2004 326 for((i=0;i<${allNodeCount};i++)) 327 do 328 echo "$staticNodes">>"./node-$i/data/static-nodes.json" 329 done 330 331 # 将文件夹拷贝到目标机器上,并启动区块链节点服务 332 # shellcheck disable=SC2004 333 for((i=0;i<${allNodeCount};i++)) 334 do 335 # shellcheck disable=SC2029 336 # ssh "${user}@${allNodeHosts[$i]}" "cd ${baseDir}/$projectDir/node-$i&&bash stop.sh" 337 338 # shellcheck disable=SC2029 339 ssh "${user}@${allNodeHosts[$i]}" "rm -rf ${baseDir}/$projectDir&&mkdir -p ${baseDir}/$projectDir" 340 341 # shellcheck disable=SC2086 342 scp -r node-$i "${user}@${allNodeHosts[$i]}:${baseDir}/$projectDir/node-$i" 343 344 # shellcheck disable=SC2029 345 ssh "${user}@${allNodeHosts[$i]}" "cd ${baseDir}/$projectDir/node-$i&&bash start.sh" 346 done 347 348 sleep "$waitPeriod" 349 350 #先确认,各个节点已经连接完成 351 expected=$((allNodeCount - 1)) 352 353 for((i=0;i<${#allNodeHosts[*]};i++)) 354 do 355 # shellcheck disable=SC2027 356 httpUrl="http://"${allNodeHosts[$i]}":$httpPort" 357 358 peerCount=$(${cmd} attach "${httpUrl}" --exec "admin.peers.length") 359 360 echo "节点 ${allNodeHosts[$i]} 连接数为:$peerCount" 361 362 # shellcheck disable=SC2086 363 if [ $peerCount != $expected ];then 364 i=0 365 sleep "$waitPeriod" 366 fi 367 done 368 369 #读取合约 370 code="0x$(<./Permission.bin)" 371 372 #取第一个节点 373 # shellcheck disable=SC2027 374 httpUrl="http://"${allNodeHosts[0]}":$httpPort" 375 376 #部署合约 377 hash=$($cmd attach "${httpUrl}" --exec "eth.sendTransaction({from:eth.accounts[0],data:\"${code}\"})") 378 379 echo "deploy contract hash:$hash" 380 381 sleep "$waitPeriod" 382 383 #根据哈希获取合约地址 384 for ((i=1; i<=3; i++)) 385 do 386 contractAddress="" 387 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 388 echo "status:$status" 389 if [ "$status" = '"0x1"' ] ;then 390 echo "contract deploy success" 391 contractAddress=$($cmd attach "${httpUrl}" --exec "eth.getTransactionReceipt($hash).contractAddress") 392 break 393 else 394 sleep "$waitPeriod" 395 fi 396 done 397 398 if [[ $contractAddress == "" ]];then 399 echo "try 3 times,fail" 400 exit 1 401 fi 402 403 # shellcheck disable=SC2164 404 cd "$workdir" 405 406 manageHashes=() 407 408 #初始的initNodeCount个节点都是管理员节点 409 # shellcheck disable=SC2004 410 for((i=0;i<${initNodeCount};i++)) 411 do 412 # shellcheck disable=SC2027 413 httpUrl="http://"${allNodeHosts[$i]}":$httpPort" 414 result=$($cmd attach "${httpUrl}" --exec "permission.setPermissionContractAddress($contractAddress)") 415 if [ "$result" != "true" ];then 416 echo "$result" 417 exit 1 418 fi 419 # shellcheck disable=SC2154 420 hash=$($cmd attach "${httpUrl}" --exec "permission.setAdminNode(${encodeNodes[$i]},\"${nodeNames[$i]}\",\"${accounts[$i]}\",eth.accounts[0])") 421 if [[ $hash == \"0x* ]];then 422 echo "hash:$hash;" 423 manageHashes[$i]=$hash 424 else 425 echo "result:$hash" 426 echo "httpUrl:${httpUrl}" 427 fi 428 done 429 # shellcheck disable=SC2053 430 if [[ ${#manageHashes[*]} != ${initNodeCount} ]];then 431 echo "Not all the setAdminNode success,want ${initNodeCount} ,got ${#manageHashes[*]}" 432 exit 1 433 fi 434 435 sleep "$waitPeriod" 436 437 #检测设置管理员节点是否全部成功,必须保证全部成功再进行下一步 438 for((i=0;i<${#manageHashes[*]};i++)) 439 do 440 # shellcheck disable=SC2027 441 httpUrl="http://"${allNodeHosts[$i]}":$httpPort" 442 hash=${manageHashes[$i]} 443 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 444 if [ "$status" = '"0x1"' ] ;then 445 echo "hash:$hash:success" 446 else 447 echo "hash:$hash:$status" 448 echo "try getTransactionReceipt again" 449 sleep "$waitPeriod" 450 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 451 if [ "$status" = '"0x1"' ] ;then 452 echo "hash:$hash:success" 453 else 454 echo "hash:$hash:$status" 455 exit 1 456 fi 457 fi 458 done 459 460 # shellcheck disable=SC2027 461 httpUrl="http://"${allNodeHosts[0]}":$httpPort" 462 463 #结束网络的初始化 464 hash=$($cmd attach "${httpUrl}" --exec "permission.initFinish(eth.accounts[0])") 465 466 sleep "$waitPeriod" 467 468 for((i=0;i<3;i++)) 469 do 470 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 471 if [ "$status" = '"0x1"' ] ;then 472 echo "hash:$hash:success" 473 echo "chain network init success" 474 break 475 else 476 echo "hash:$hash:$status" 477 echo "try again" 478 sleep "$waitPeriod" 479 fi 480 done 481 482 applyHashes=() 483 #用第一个节点为普通节点申请加入网络 484 # shellcheck disable=SC2004 485 for((i=$initNodeCount;i<$allNodeCount;i++)) 486 do 487 #必须给节点设置好合约地址,否则调用permission的接口各种method handler crashed 488 hash=$($cmd attach "${httpUrl}" --exec "permission.makeProposalForJoin(${encodeNodes[$i]},\"${nodeNames[$i]}\",\"${accounts[$i]}\",eth.accounts[0])") 489 if [[ $hash == \"0x* ]];then 490 echo "makeProposalForJoin hash:$hash;" 491 applyHashes[(($i-$initNodeCount))]=$hash #要从0开始 492 fi 493 done 494 495 #稍等一个块的时间 496 sleep "$waitPeriod" 497 498 for((i=0;i<${#applyHashes[*]};i++)) 499 do 500 hash=${applyHashes[$i]} 501 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 502 if [ "$status" = '"0x1"' ] ;then 503 echo "makeProposalForJoin hash:$hash:success" 504 else 505 echo "hash:$hash:$status" 506 echo "try makeProposalForJoin getTransactionReceipt again" 507 sleep "$waitPeriod" 508 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 509 if [ "$status" = '"0x1"' ] ;then 510 echo "makeProposalForJoin hash:$hash:success" 511 else 512 echo "hash:$hash:$status" 513 exit 1 514 fi 515 fi 516 done 517 518 519 520 verifyHashes=() 521 # shellcheck disable=SC2004 522 for((i=0;i<${initNodeCount};i++)) 523 do 524 #连接管理员节点 525 # shellcheck disable=SC2027 526 httpUrl="http://"${allNodeHosts[$i]}":$httpPort" 527 #管理员节点给每个节点投一票 528 for((k=$initNodeCount;k<$allNodeCount;k++)) 529 do 530 hash=$($cmd attach "${httpUrl}" --exec "permission.acceptProposalForJoin(${encodeNodes[$k]},eth.accounts[0])") 531 if [[ $hash == \"0x* ]];then 532 echo "acceptProposalForJoin hash:$hash;" 533 verifyHashes[${#verifyHashes[@]}]=$hash 534 fi 535 done 536 done 537 538 #稍等一个块的时间 539 sleep "$waitPeriod" 540 541 for((i=0;i<${#verifyHashes[*]};i++)) 542 do 543 hash=${verifyHashes[$i]} 544 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 545 if [ "$status" = '"0x1"' ] ;then 546 echo "acceptProposalForJoin hash:$hash:success" 547 else 548 echo "hash:$hash:$status" 549 echo "try acceptProposalForJoin getTransactionReceipt again" 550 sleep "$waitPeriod" 551 status=$($cmd attach "${httpUrl}" --exec "var receipt=eth.getTransactionReceipt($hash);if(receipt!=null){receipt.status}") 552 if [ "$status" = '"0x1"' ] ;then 553 echo "acceptProposalForJoin hash:$hash:success" 554 else 555 echo "hash:$hash:$status" 556 fi 557 fi 558 done 559 560 561 #为普通节点设置合约地址 562 # shellcheck disable=SC2004 563 for((i=$initNodeCount;i<$allNodeCount;i++)) 564 do 565 #必须给节点设置好合约地址,否则调用permission的接口各种method handler crashed 566 # shellcheck disable=SC2027 567 httpUrl="http://"${allNodeHosts[$i]}":$httpPort" 568 $cmd attach "${httpUrl}" --exec "permission.setPermissionContractAddress($contractAddress)" 569 done 570 571 # shellcheck disable=SC2027 572 httpUrl="http://"${allNodeHosts[0]}":$httpPort" 573 574 # shellcheck disable=SC2004 575 for((k=$initNodeCount;k<$allNodeCount;k++)) 576 do 577 hash=$($cmd attach "${httpUrl}" --exec "permission.getNodeInfo(${encodeNodes[$k]},eth.accounts[0])") 578 echo "nodeInfo:$hash;"Ï 579 done 580 581 end=$(date +%s) 582 583 delta=$((end-start)) 584 585 echo "cost $delta seconds." 586 587 #set +x