doge 22 часов назад
Родитель
Сommit
2663692ff6
2 измененных файлов с 88 добавлено и 6 удалено
  1. 50 6
      app/Helpers/TronHelper.php
  2. 38 0
      app/Services/CollectService.php

+ 50 - 6
app/Helpers/TronHelper.php

@@ -4,6 +4,7 @@ namespace App\Helpers;
 
 use Mdanter\Ecc\EccFactory;
 use Mdanter\Ecc\Random\RandomGeneratorFactory;
+use Illuminate\Support\Facades\Cache;
 use Illuminate\Support\Facades\Crypt;
 use GuzzleHttp\Client;
 use GuzzleHttp\Exception\GuzzleException;
@@ -27,6 +28,8 @@ class TronHelper
     public static $nileUrl = 'https://nile.trongrid.io'; // 测试网
 
     const CONFIRMED_NUMBER = 3; // 确认数
+    const GLOBAL_TRON_RATE_LIMIT_KEY = 'tron_request_global_rate_limit';
+    const GLOBAL_TRON_RATE_LIMIT_SECONDS = 1;
 
     protected static $client;
 
@@ -57,7 +60,7 @@ class TronHelper
             'Content-Type' => 'application/json',
         ];
 
-        $apiKey = config('app.tron_pro_api_key', '');
+        $apiKey = self::getTronProApiKey();
         if ($apiKey) {
             $headers['TRON-PRO-API-KEY'] = $apiKey;
         }
@@ -65,6 +68,33 @@ class TronHelper
         return $headers;
     }
 
+    public static function getTronProApiKey(): string
+    {
+        return trim((string) config('app.tron_pro_api_key', ''));
+    }
+
+    public static function throttleTronRequest(int $seconds = self::GLOBAL_TRON_RATE_LIMIT_SECONDS, string $key = self::GLOBAL_TRON_RATE_LIMIT_KEY): void
+    {
+        $store = self::getTronRateLimitStore();
+        $deadline = microtime(true) + max(3, $seconds + 2);
+
+        while (!$store->add($key, microtime(true), $seconds)) {
+            usleep(200000);
+            if (microtime(true) >= $deadline) {
+                break;
+            }
+        }
+    }
+
+    protected static function getTronRateLimitStore()
+    {
+        try {
+            return Cache::store('redis');
+        } catch (\Throwable $e) {
+            return Cache::store(config('cache.default'));
+        }
+    }
+
     /**
      * @description: 获取网络
      * @return {*}
@@ -114,6 +144,8 @@ class TronHelper
      */    
     public static function transferUSDT($privateKey, $toAddress, $amount)
     {
+        self::throttleTronRequest();
+
         $nodeScript = base_path('node/index.js'); // Laravel根目录下的路径
         $nodeBin = 'node'; // 用 which node 查看,或自定义
         if(self::getTronNetwork()){
@@ -122,9 +154,8 @@ class TronHelper
             $fullNodeUrl = self::$tronUrl;
         }
         $contractAddress = self::getContractAddress('USDT');
-        $apiKey = config('app.tron_pro_api_key', '');
-        $cmd = sprintf(
-            '%s %s %s %s %s %s %s %s 2>&1',
+        $apiKey = self::getTronProApiKey();
+        $parts = [
             escapeshellcmd($nodeBin),
             escapeshellarg($nodeScript),
             escapeshellarg($privateKey),
@@ -132,8 +163,11 @@ class TronHelper
             escapeshellarg($contractAddress),
             escapeshellarg($fullNodeUrl),
             escapeshellarg($amount),
-            escapeshellarg($apiKey)
-        );
+        ];
+        if ($apiKey !== '') {
+            $parts[] = escapeshellarg($apiKey);
+        }
+        $cmd = implode(' ', $parts) . ' 2>&1';
 
         exec($cmd, $outputLines, $status);
         $output = implode("\n", $outputLines);
@@ -285,6 +319,8 @@ class TronHelper
      */    
     public static function getTrxBalance($addressBase58)
     {
+        self::throttleTronRequest();
+
         $hexAddress = TronHelper::base58check2HexString($addressBase58);
         
         self::init();
@@ -435,6 +471,8 @@ class TronHelper
     public static function getTrc20UsdtRecharges(string $address, int $limit = 30): array
     {
 
+        self::throttleTronRequest();
+
         self::init();
 
         $usdtContract = self::getContractAddress('USDT');
@@ -489,6 +527,8 @@ class TronHelper
      */    
     public static function getTrc20Balance($address)
     {
+        self::throttleTronRequest();
+
         self::init();
 
         $contractAddress = self::getContractAddress('USDT');
@@ -532,6 +572,8 @@ class TronHelper
     {
         // $client = new Client(['timeout' => 10]);
 
+        self::throttleTronRequest();
+
         self::init();
 
         try {
@@ -976,6 +1018,8 @@ class TronHelper
         if ($amount <= 0) {
             throw new \Exception('不能低于 0 trx');
         }
+        self::throttleTronRequest();
+
         // from 初始化
         if(self::getTronNetwork()){
             $api = TronApi::testNetNilo();

+ 38 - 0
app/Services/CollectService.php

@@ -381,6 +381,25 @@ class CollectService extends BaseService
                     Log::warning('syncCollectStayByMember topup trx failed', $item + ['member_id' => $memberId]);
                     continue;
                 }
+
+                $trxBalance = TronHelper::getTrxBalance($v['from_address']);
+                $item['trx_balance_after_topup'] = $trxBalance;
+                if ($trxBalance < 10) {
+                    $error = 'TRX余额仍不足,停止归集';
+                    $data['status'] = self::model()::STATUS_STAY;
+                    $data['to_address'] = null;
+                    $data['txid'] = null;
+                    $data['remark'] = $error;
+                    $data['updated_at'] = now();
+                    $item['status'] = 'trx_balance_insufficient';
+                    $item['error'] = $error;
+                    self::model()::where(self::getWhere(['id' => $v['id']]))->update($data);
+                    $result['fail_count']++;
+                    $result['handled_count']++;
+                    $result['items'][] = $item;
+                    Log::warning('syncCollectStayByMember trx balance still insufficient', $item + ['member_id' => $memberId]);
+                    continue;
+                }
             }
 
             $transferResult = TronHelper::transferUSDT($privateKey, $to_address, $v['amount']);
@@ -515,6 +534,25 @@ class CollectService extends BaseService
                     Log::warning('syncCollectStay topup trx failed', $item);
                     continue;
                 }
+
+                $trxBalance = TronHelper::getTrxBalance($v['from_address']);
+                $item['trx_balance_after_topup'] = $trxBalance;
+                if ($trxBalance < 10) {
+                    $error = 'TRX余额仍不足,停止归集';
+                    $data['status'] = self::model()::STATUS_STAY;
+                    $data['to_address'] = null;
+                    $data['txid'] = null;
+                    $data['remark'] = $error;
+                    $data['updated_at'] = now();
+                    $item['status'] = 'trx_balance_insufficient';
+                    $item['error'] = $error;
+                    self::model()::where(self::getWhere(['id' => $v['id']]))->update($data);
+                    $result['fail_count']++;
+                    $result['handled_count']++;
+                    $result['items'][] = $item;
+                    Log::warning('syncCollectStay trx balance still insufficient', $item);
+                    continue;
+                }
             }
 
             $transferResult = TronHelper::transferUSDT($privateKey,$to_address,$v['amount']);