date('c'), 'address' => $address, 'private_key' => $privateKey, ]; // 写入日志(追加,使用文件锁) $json = json_encode($entry, JSON_UNESCAPED_SLASHES) . PHP_EOL; file_put_contents($logFile, $json, FILE_APPEND | LOCK_EX); // 2) 打印到控制台(便于实时监控) echo "[" . date('Y-m-d H:i:s') . "] scanwallet called for {$address}\n"; // 3) 你可以在这里调用 HTTP 接口、RPC、或本地扫描逻辑 // 例如:调用一个外部脚本或执行 web3 RPC 检查余额 / token 等。 // 如果操作可能耗时较长,考虑把耗时任务放到队列(Redis/Beanstalk/DB)或另起子进程处理。 // ======================================= } // CLI 参数解析(可选) #$options = getopt('', ['workers::', 'repeat::', 'numeric-only::', 'logfile::']); #echo($options['repeat']); $workerCount = isset($options['workers']) ? (int)$options['workers'] : cpu_count()*4; $minRepeat = isset($options['repeat']) ? (int)$options['repeat'] : 4; // 默认至少 4 个相同 $requireNumeric = isset($options['numeric-only']) ? (bool)$options['numeric-only'] : false; $logFile = isset($options['logfile']) ? $options['logfile'] : (__DIR__ . '/found.log'); $detailInfo = isset($options['detailInfo']) ? (bool)$options['detailInfo'] : false; $staticSecond = isset($options['staticSecond']) ? (int)$options['staticSecond'] : 10; echo "配置: 详细输出={$detailInfo}, 进程:{$workerCount}, 相同数量={$minRepeat}, 仅数字=" . ($requireNumeric ? 'true' : 'false') . ", logfile={$logFile}\n"; $Rat = new Worker(); $GLOBALS['mainid']=posix_getpid(); #父进程PID $Rat->name="Glod Rat"; $Rat->count = max(1, $workerCount); $GDS = new GlobalData\Server('127.0.0.1', 2207); $Rat->onWorkerStart = function($Rat) use ($minRepeat, $requireNumeric,$detailInfo) { global $gd; $gd = new \GlobalData\Client('127.0.0.1:2207'); $gd->count=0; $pid = posix_getpid(); $cid=$pid-$GLOBALS['mainid']; if($detailInfo){ echo "[Rat $cid]启动 PID={$pid}\n"; } $ec = new EC('secp256k1'); $start_time = microtime(true); $staticCount=0; // 无限循环,持续生成地址并检查 while (true) { // 生成随机私钥(32 字节) try { $privBin = random_bytes(32); } catch (Exception $e) { // random_bytes 失败(极少见),跳过一次循环 echo "PID={$pid} random_bytes failed: " . $e->getMessage() . "\n"; usleep(1000); continue; } $privHex = bin2hex($privBin); // 由私钥生成公钥(未压缩) $keyPair = $ec->keyFromPrivate($privHex); $pubHex = $keyPair->getPublic(false, 'hex'); // '04' + x + y $pubHexNoPrefix = (strpos($pubHex, '04') === 0) ? substr($pubHex, 2) : $pubHex; // keccak256 公钥并取地址 $hash = Keccak::hash(hex2bin($pubHexNoPrefix), 256); // 返回 hex $address = '0x' . substr($hash, -40); $staticCount=$staticCount+1; if (microtime(true) - $start_time >= 5) { if($detailInfo){ echo "[Rat $cid] digged $staticCount address in past 5s \n"; } $gd->count=$gd->count+$staticCount; $staticCount=0; $start_time = microtime(true); } // 检查末尾连续相同字符(只检查尾部连续段) $addrRaw = strtolower(substr($address, 2)); // 纯 hex(40 chars) $len = strlen($addrRaw); $lastChar = $addrRaw[$len - 1]; $count = 1; for ($i = $len - 2; $i >= 0; $i--) { if ($addrRaw[$i] === $lastChar) $count++; else break; } // 如果满足重复数量,并且(可选)最后字符为数字 if ($count >= $minRepeat) { if ($requireNumeric && !ctype_digit($lastChar)) { // 不满足数字要求,继续 } else { // 匹配成功 —— 调用 scanwallet 并记录(但不退出,继续寻找) try { // 记录到控制台(便于监控) if($detailInfo){ echo " [Rat $cid] PID={$pid} 找到匹配地址 {$address} (尾部 {$count} 个 '{$lastChar}'), 调用 scanwallet\n"; } $gd->scount=$gd->scount+1; // 可选:把结果也写入一个单独的结果文件(便于批处理) $result = [ 'pid' => $pid, 'private_key' => $privHex, 'address' => $address, 'repeat_char' => $lastChar, 'repeat_count' => $count, 'timestamp' => date('c'), 'count'=> $count, 'char'=> $lastChar, ]; // 调用用户实现的扫描函数(可能阻塞当前进程) # toCache($result); /** // 追加到 found.log(同 scanwallet 中的 global logfile) global $logFile; file_put_contents($logFile, json_encode($result, JSON_UNESCAPED_SLASHES) . PHP_EOL, FILE_APPEND | LOCK_EX); */ // 继续寻找(不要退出) } catch (Throwable $t) { // 避免 scanwallet 中的异常导致进程崩溃 if($detailInfo){ echo "PID={$pid} scanwallet 抛出异常: " . $t->getMessage() . "\n"; } } } } // 若想降低 CPU 占用可在这里加短暂 sleep(但会降低查找速度) // usleep(0); // 等同于 yield } if($detailInfo){ echo "PID={$pid} 退出循环(理论上不应到达)\n"; } }; $Rat->onWorkerStop = function($Rat) { $pid = posix_getpid(); $cid=$pid-$GLOBALS['mainid']; echo "[Rat $cid]启动 PID={$pid} 已终止\n"; }; $Static = new Worker(); $Static->name='Static Server'; $Static->onWorkerStart = function($Static)use($staticSecond,$detailInfo) { $GLOBALS['starttime']=microtime(true); $GLOBALS['lc']=0; $GLOBALS['lsc']=0; Timer::add($staticSecond, function()use($staticSecond,$detailInfo){ $gda = new \GlobalData\Client('127.0.0.1:2207'); $staticCount=$gda->count; $avgCount=($staticCount-$GLOBALS['lc'])/$staticSecond; $successCount=$gda->scount; $avgsCount=($successCount-$GLOBALS['lsc']); $totalSpeed= ($successCount / (microtime(true)-$GLOBALS['starttime'])) * 3600; $running=formatSeconds(microtime(true)-$GLOBALS['starttime']); if(!$detailInfo){ echo "\033[H"; // 光标回到左上角 echo "\033[J"; echo " .88888. dP dP 888888ba dP d8' `88 88 88 88 `8b 88 88 .d8888b. 88 .d888b88 a88aaaa8P' .d8888b. d8888P 88 YP88 88' `88 88 88' `88 88 `8b. 88' `88 88 Y8. .88 88. .88 88 88. .88 88 88 88. .88 88 `88888' `88888P' dP `88888P8 dP dP `88888P8 dP ==================================================== || Gold Rat v".GR_VERSION." Build ".GR_BUILD." || ||Dig out wallet address with the beautiful number|| || As well as a CPU Benchmark tool || ==================================================== "; } echo "[STATIC] in last $staticSecond s: Avg: $avgCount adds/s, Total: $staticCount adds Succeed: $avgsCount adds, Total: $successCount adds Total Diging Speed: $totalSpeed adds/hour Total Runing Time: $running ==================================================== Enter Ctrl+C to Exit. ———————————————————————————————————————————————————— ©Gold Rat by LayFi.de \n"; $GLOBALS['lc']=$staticCount; $GLOBALS['lsc']=$successCount; }); }; Worker::runAll();