220 lines
8.8 KiB
PHP
220 lines
8.8 KiB
PHP
<?php
|
||
// start.php
|
||
require __DIR__ . '/vendor/autoload.php';
|
||
require __DIR__ . '/helper.php';
|
||
require __DIR__ . '/config.php';
|
||
require __DIR__ . '/version.php';
|
||
|
||
use Workerman\Worker;
|
||
use Elliptic\EC;
|
||
use kornrunner\Keccak;
|
||
use Workerman\Timer;
|
||
|
||
|
||
// 你应该实现这个函数:发现地址后要做的事(扫描、转账、上报等)
|
||
// 这里只给出一个示例实现:异步-safe 的日志 + 简单输出。
|
||
// 请根据你实际需要替换或扩展该函数内容。
|
||
// 注意:这个函数在各个子进程中同步执行(阻塞该进程直至返回)。
|
||
function scanwallet(string $address, string $privateKey): void {
|
||
// === 示例逻辑(请替换为真实逻辑) ===
|
||
// 1) 记录到日志文件(追加)
|
||
global $logFile;
|
||
$entry = [
|
||
'timestamp' => 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();
|