Files
gh-icehugh-web3-skills-plug…/skills/walrus-debugger.md
2025-11-29 18:47:53 +08:00

22 KiB
Raw Blame History

name, description, parameters
name description parameters
walrus-debugger Walrus 错误诊断专家 - 智能分析和解决 Walrus 应用中的问题
name type description required
error-type string 错误类型 (upload/download/network/configuration/timeout/authentication) true
name type description required
error-context string 错误信息、代码片段或问题描述 true
name type description default
environment string 运行环境 (browser/nodejs/nextjs/production) nodejs

Walrus 错误诊断技能

技能概述

walrus-debugger 是专业的错误诊断助手,专门分析 Walrus 应用中的各种问题,提供智能的解决方案和预防措施。

常见错误类型及解决方案

1. 上传失败错误

错误类型: Upload Failed

// 错误示例
Error: Upload failed: insufficient storage balance
Error: Upload failed: blob size exceeds maximum limit
Error: Upload failed: transaction rejected

// 诊断和解决方案
class UploadErrorDiagnostics {
  async diagnoseUploadError(error: Error, context: UploadContext): Promise<Diagnosis> {
    const analysis = this.analyzeErrorMessage(error.message);

    switch (analysis.type) {
      case 'INSUFFICIENT_BALANCE':
        return this.diagnoseBalanceError(context);
      case 'SIZE_LIMIT':
        return this.diagnoseSizeError(context);
      case 'TRANSACTION_REJECTED':
        return this.diagnoseTransactionError(error, context);
      case 'TIMEOUT':
        return this.diagnoseTimeoutError(context);
      default:
        return this.diagnoseGenericUploadError(error, context);
    }
  }

  private async diagnoseBalanceError(context: UploadContext): Promise<Diagnosis> {
    const walletBalance = await this.checkWalletBalance(context.signerAddress);

    return {
      errorType: 'INSUFFICIENT_BALANCE',
      description: '钱包余额不足,无法支付存储费用',
      causes: [
        'WAL 代币余额不足',
        'SUI 代币余额不足以支付 gas 费',
        '存储成本计算错误'
      ],
      solutions: [
        {
          title: '检查并充值钱包',
          code: `
// 检查钱包余额
async function checkBalances(address: string) {
  const suiClient = new SuiClient({ url: getFullnodeUrl('testnet') });
  const balance = await suiClient.getBalance({ owner: address });

  console.log('SUI Balance:', balance.totalBalance);

  // 检查 WAL 余额(如果支持)
  const walBalance = await suiClient.getBalance({
    owner: address,
    coinType: '0x2::sui::SUI' // 替换为 WAL coin type
  });

  return { sui: balance.totalBalance, wal: walBalance.totalBalance };
}`
        },
        {
          title: '优化存储策略',
          code: `
// 使用更短的存储周期
const result = await client.walrus.writeFiles({
  files: [file],
  epochs: 5, // 减少存储周期
  deletable: true,
  signer: keypair
});

// 或者使用更小的文件
function compressFile(file: File): Promise<File> {
  return new Promise((resolve) => {
    if (file.size > 10 * 1024 * 1024) { // 10MB
      // 压缩或分割文件
      compressImage(file).then(resolve);
    } else {
      resolve(file);
    }
  });
}`
        }
      ],
      prevention: [
        '定期检查钱包余额',
        '设置余额预警',
        '实施费用估算功能'
      ]
    };
  }

  private async diagnoseSizeError(context: UploadContext): Promise<Diagnosis> {
    const fileStats = await this.analyzeFileSize(context.file);

    return {
      errorType: 'SIZE_LIMIT',
      description: '文件大小超出限制',
      causes: [
        `文件大小 ${fileStats.size}MB 超出限制`,
        '网络环境不支持大文件传输',
        '客户端内存不足'
      ],
      solutions: [
        {
          title: '文件压缩',
          code: `
// 图片压缩
async function compressImage(file: File, quality = 0.8): Promise<File> {
  return new Promise((resolve) => {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d')!;
    const img = new Image();

    img.onload = () => {
      // 计算压缩后的尺寸
      const scale = Math.min(1, 1920 / Math.max(img.width, img.height));
      canvas.width = img.width * scale;
      canvas.height = img.height * scale;

      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

      canvas.toBlob((blob) => {
        resolve(new File([blob!], file.name, { type: file.type }));
      }, file.type, quality);
    };

    img.src = URL.createObjectURL(file);
  });
}

// 文本文件压缩
async function compressTextFile(file: File): Promise<File> {
  const text = await file.text();
  const compressed = await this.compressString(text);
  return new File([compressed], file.name + '.gz', { type: 'application/gzip' });
}`
        },
        {
          title: '文件分割上传',
          code: `
// 分割大文件
async function splitAndUpload(file: File, chunkSize = 5 * 1024 * 1024): Promise<string[]> {
  const chunks: string[] = [];
  const totalChunks = Math.ceil(file.size / chunkSize);

  for (let i = 0; i < totalChunks; i++) {
    const start = i * chunkSize;
    const end = Math.min(start + chunkSize, file.size);
    const chunk = file.slice(start, end);

    const chunkFile = new File([chunk], \`\${file.name}.part\${i}\`);
    const result = await uploadSingleFile(chunkFile);
    chunks.push(result.blobId);
  }

  return chunks;
}

// 创建清单文件记录分割信息
async function createManifest(chunks: string[], originalFile: File): Promise<string> {
  const manifest = {
    originalName: originalFile.name,
    originalSize: originalFile.size,
    chunks: chunks.map((blobId, index) => ({
      blobId,
      index,
      size: originalFile.size / chunks.length
    }))
  };

  const manifestBlob = new Blob([JSON.stringify(manifest)], { type: 'application/json' });
  const manifestFile = new File([manifestBlob], \`\${originalFile.name}.manifest\`);

  const result = await uploadSingleFile(manifestFile);
  return result.blobId;
}`
        }
      ],
      prevention: [
        '预先检查文件大小',
        '实施文件大小限制',
        '提供文件压缩工具'
      ]
    };
  }
}

2. 网络连接错误

错误类型: Network Error

// 错误示例
Error: Network timeout
Error: Connection refused
Error: Failed to fetch

class NetworkErrorDiagnostics {
  async diagnoseNetworkError(error: Error, context: NetworkContext): Promise<Diagnosis> {
    const networkStatus = await this.checkNetworkStatus();

    return {
      errorType: 'NETWORK_ERROR',
      description: '网络连接问题',
      causes: [
        '网络连接不稳定',
        'RPC 节点不可用',
        '防火墙或代理阻止连接',
        'DNS 解析失败'
      ],
      solutions: [
        {
          title: '实施自动重试机制',
          code: `
class RobustWalrusClient {
  private readonly MAX_RETRIES = 3;
  private readonly RETRY_DELAY_BASE = 1000;

  async withRetry<T>(
    operation: () => Promise<T>,
    operationName: string
  ): Promise<T> {
    for (let attempt = 1; attempt <= this.MAX_RETRIES; attempt++) {
      try {
        return await operation();
      } catch (error) {
        if (!this.isRetryableError(error) || attempt === this.MAX_RETRIES) {
          throw new Error(\`\${operationName} failed after \${attempt} attempts: \${error.message}\`);
        }

        const delay = this.RETRY_DELAY_BASE * Math.pow(2, attempt - 1);
        console.warn(\`\${operationName} failed (attempt \${attempt}/\${this.MAX_RETRIES}), retrying in \${delay}ms\`);

        await this.sleep(delay);
      }
    }

    throw new Error('Should not reach here');
  }

  private isRetryableError(error: any): boolean {
    return error instanceof RetryableWalrusClientError ||
           error.message.includes('timeout') ||
           error.message.includes('network') ||
           error.message.includes('connection') ||
           error.status >= 500; // Server errors
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  async uploadFiles(files: WalrusFile[]): Promise<any> {
    return this.withRetry(
      () => this.client.walrus.writeFiles({ files, epochs: 10, signer: this.signer }),
      'File upload'
    );
  }
}`
        },
        {
          title: '实施节点健康检查',
          code: `
// 节点健康检查
class NodeHealthChecker {
  private nodes: string[] = [
    'https://fullnode.testnet.sui.io',
    'https://fullnode.testnet.sui.io:443',
    // 添加备用节点
  ];

  async getHealthyNode(): Promise<string> {
    for (const node of this.nodes) {
      try {
        const response = await fetch(\`\${node}/\`, {
          method: 'HEAD',
          timeout: 5000
        });

        if (response.ok) {
          console.log(\`Node \${node} is healthy\`);
          return node;
        }
      } catch (error) {
        console.warn(\`Node \${node} is unhealthy: \${error.message}\`);
      }
    }

    throw new Error('No healthy nodes available');
  }

  async testAllNodes(): Promise<NodeHealth[]> {
    const results = await Promise.allSettled(
      this.nodes.map(async (node) => {
        const startTime = Date.now();
        try {
          const response = await fetch(\`\${node}/\`, { method: 'HEAD', timeout: 5000 });
          return {
            node,
            healthy: response.ok,
            responseTime: Date.now() - startTime,
            error: null
          };
        } catch (error) {
          return {
            node,
            healthy: false,
            responseTime: Date.now() - startTime,
            error: error.message
          };
        }
      })
    );

    return results.map(result =>
      result.status === 'fulfilled' ? result.value : null
    ).filter(Boolean) as NodeHealth[];
  }
}`
        },
        {
          title: '配置超时和重试',
          code: `
// 配置自定义超时和重试
const client = new SuiJsonRpcClient({
  url: getFullnodeUrl('testnet'),
  network: 'testnet',
}).$extend(walrus({
  storageNodeClientOptions: {
    timeout: 60000, // 60秒超时
    retryAttempts: 5,
    retryDelay: 2000,
    onError: (error) => {
      console.error('Storage node error:', error);
      // 发送错误到监控系统
      this.trackError('storage_node_error', error);
    }
  }
}));`
        }
      ],
      prevention: [
        '实施网络监控',
        '使用多个备用节点',
        '设置合理的超时时间',
        '实施断路器模式'
      ]
    };
  }

  private async checkNetworkStatus(): Promise<NetworkStatus> {
    try {
      const response = await fetch('https://httpbin.org/ip');
      const ipInfo = await response.json();

      return {
        online: true,
        ip: ipInfo.ip,
        latency: Date.now() - this.startTime
      };
    } catch (error) {
      return {
        online: false,
        error: error.message
      };
    }
  }
}

3. 配置错误

错误类型: Configuration Error

// 错误示例
Error: Invalid network configuration
Error: WASM module failed to load
Error: Invalid signer configuration

class ConfigurationErrorDiagnostics {
  async diagnoseConfigError(error: Error, context: ConfigContext): Promise<Diagnosis> {
    return {
      errorType: 'CONFIGURATION_ERROR',
      description: '配置问题',
      causes: [
        '网络配置错误',
        'WASM 模块路径错误',
        '签名者配置无效',
        '环境变量缺失'
      ],
      solutions: [
        {
          title: '验证配置完整性',
          code: `
// 配置验证器
class ConfigValidator {
  static validateWalrusConfig(config: any): ValidationResult {
    const errors: string[] = [];

    // 验证必需字段
    if (!config.network) {
      errors.push('network is required (testnet/mainnet)');
    }

    if (!config.rpcUrl) {
      errors.push('rpcUrl is required');
    }

    // 验证网络配置
    if (config.network && !['testnet', 'mainnet'].includes(config.network)) {
      errors.push('network must be either "testnet" or "mainnet"');
    }

    // 验证 URL 格式
    if (config.rpcUrl && !this.isValidUrl(config.rpcUrl)) {
      errors.push('rpcUrl must be a valid URL');
    }

    // 验证超时配置
    if (config.timeout && (config.timeout < 1000 || config.timeout > 300000)) {
      errors.push('timeout must be between 1000ms and 300000ms');
    }

    return {
      valid: errors.length === 0,
      errors
    };
  }

  static async validateEnvironment(): Promise<ValidationResult> {
    const errors: string[] = [];

    // 检查环境变量
    const requiredEnvVars = ['WALRUS_NETWORK', 'SUI_RPC_URL'];
    for (const envVar of requiredEnvVars) {
      if (!process.env[envVar]) {
        errors.push(\`Environment variable \${envVar} is required\`);
      }
    }

    // 检查 WASM 支持
    if (typeof window !== 'undefined' && !window.WebAssembly) {
      errors.push('WebAssembly is not supported in this browser');
    }

    // 验证网络连接
    try {
      const response = await fetch(process.env.SUI_RPC_URL!, {
        method: 'HEAD',
        timeout: 5000
      });
      if (!response.ok) {
        errors.push('Cannot connect to SUI RPC endpoint');
      }
    } catch (error) {
      errors.push(\`Network connection failed: \${error.message}\`);
    }

    return {
      valid: errors.length === 0,
      errors
    };
  }

  private static isValidUrl(string: string): boolean {
    try {
      new URL(string);
      return true;
    } catch {
      return false;
    }
  }
}

// 使用配置验证
const config = {
  network: 'testnet',
  rpcUrl: getFullnodeUrl('testnet'),
  timeout: 30000
};

const validation = ConfigValidator.validateWalrusConfig(config);
if (!validation.valid) {
  console.error('Configuration validation failed:', validation.errors);
  throw new Error('Invalid configuration');
}`
        },
        {
          title: 'WASM 模块配置',
          code: `
// WASM 配置验证和加载
class WasmLoader {
  static async loadWasmWithFallback(): Promise<any> {
    const strategies = [
      () => this.loadFromBundle(),
      () => this.loadFromCDN(),
      () => this.loadFromLocal()
    ];

    for (const strategy of strategies) {
      try {
        const wasm = await strategy();
        console.log('WASM loaded successfully');
        return wasm;
      } catch (error) {
        console.warn('WASM loading strategy failed:', error.message);
      }
    }

    throw new Error('All WASM loading strategies failed');
  }

  private static async loadFromBundle(): Promise<any> {
    // Vite 示例
    if (typeof import.meta !== 'undefined' && import.meta.url) {
      const wasmUrl = new URL('@mysten/walrus-wasm/web/walrus_wasm_bg.wasm', import.meta.url);
      const wasmModule = await import(wasmUrl);
      return wasmModule.default;
    }
    throw new Error('Bundle loading not supported');
  }

  private static async loadFromCDN(): Promise<any> {
    const cdnUrls = [
      'https://unpkg.com/@mysten/walrus-wasm@latest/web/walrus_wasm_bg.wasm',
      'https://cdn.jsdelivr.net/npm/@mysten/walrus-wasm@latest/web/walrus_wasm_bg.wasm'
    ];

    for (const url of cdnUrls) {
      try {
        const response = await fetch(url);
        if (response.ok) {
          const wasmBuffer = await response.arrayBuffer();
          return WebAssembly.compile(wasmBuffer);
        }
      } catch (error) {
        console.warn(\`CDN loading failed for \${url}:\`, error.message);
      }
    }

    throw new Error('All CDN URLs failed');
  }

  private static async loadFromLocal(): Promise<any> {
    // 尝试从本地路径加载
    const localPaths = [
      '/walrus/walrus_wasm_bg.wasm',
      './node_modules/@mysten/walrus-wasm/web/walrus_wasm_bg.wasm'
    ];

    for (const path of localPaths) {
      try {
        const response = await fetch(path);
        if (response.ok) {
          const wasmBuffer = await response.arrayBuffer();
          return WebAssembly.compile(wasmBuffer);
        }
      } catch (error) {
        console.warn(\`Local loading failed for \${path}:\`, error.message);
      }
    }

    throw new Error('Local loading failed');
  }
}

// 在客户端配置中使用 WASM
const client = new SuiJsonRpcClient({
  url: getFullnodeUrl('testnet'),
  network: 'testnet',
}).$extend(
  walrus({
    wasmUrl: await WasmLoader.loadWasmWithFallback()
  })
);`
        }
      ],
      prevention: [
        '实施配置验证',
        '提供配置模板',
        '设置默认值',
        '实施配置监控'
      ]
    };
  }
}

4. 浏览器环境特定错误

错误类型: Browser Environment Error

class BrowserErrorDiagnostics {
  async diagnoseBrowserError(error: Error, context: BrowserContext): Promise<Diagnosis> {
    return {
      errorType: 'BROWSER_ERROR',
      description: '浏览器环境特定问题',
      causes: [
        'WASM 不支持',
        'CORS 策略阻止',
        '内存不足',
        '钱包连接问题'
      ],
      solutions: [
        {
          title: '浏览器兼容性检查',
          code: `
// 浏览器兼容性检查
class BrowserCompatibility {
  static checkCompatibility(): BrowserCompatibilityResult {
    const checks = {
      webAssembly: this.checkWebAssembly(),
      fetch: this.checkFetch(),
      blob: this.checkBlob(),
      fileAPI: this.checkFileAPI(),
      webWorkers: this.checkWebWorkers(),
      localStorage: this.checkLocalStorage()
    };

    const supported = Object.values(checks).every(check => check.supported);

    return {
      supported,
      checks,
      recommendations: this.getRecommendations(checks)
    };
  }

  private static checkWebAssembly(): CompatibilityCheck {
    const supported = typeof WebAssembly === 'object' && WebAssembly !== null;
    return {
      supported,
      message: supported ? 'WebAssembly is supported' : 'WebAssembly is not supported',
      fix: !supported ? 'Please use a modern browser that supports WebAssembly' : null
    };
  }

  private static getRecommendations(checks: Record<string, CompatibilityCheck>): string[] {
    const recommendations: string[] = [];

    if (!checks.webAssembly.supported) {
      recommendations.push('Upgrade to a modern browser (Chrome 57+, Firefox 52+, Safari 11+)');
    }

    if (!checks.webWorkers.supported) {
      recommendations.push('Consider enabling Web Workers for better performance');
    }

    return recommendations;
  }
}

// 使用兼容性检查
const compatibility = BrowserCompatibility.checkCompatibility();
if (!compatibility.supported) {
  console.error('Browser compatibility issues:', compatibility.recommendations);
  // 显示用户友好的错误信息
  this.showCompatibilityError(compatibility);
}`
        },
        {
          title: '内存管理',
          code: `
// 浏览器内存管理
class BrowserMemoryManager {
  private memoryThreshold = 100 * 1024 * 1024; // 100MB

  async checkMemoryUsage(): Promise<MemoryUsage> {
    if ('memory' in performance) {
      const memory = (performance as any).memory;
      return {
        used: memory.usedJSHeapSize,
        total: memory.totalJSHeapSize,
        limit: memory.jsHeapSizeLimit,
        usageRatio: memory.usedJSHeapSize / memory.jsHeapSizeLimit
      };
    }
    return { used: 0, total: 0, limit: 0, usageRatio: 0 };
  }

  async manageMemoryForLargeFile(file: File): Promise<boolean> {
    const memoryUsage = await this.checkMemoryUsage();

    // 检查是否有足够内存处理文件
    const estimatedUsage = file.size * 3; // 估算处理过程中需要的内存
    const availableMemory = memoryUsage.limit - memoryUsage.used;

    if (estimatedUsage > availableMemory) {
      console.warn('Insufficient memory for file processing');

      // 触发垃圾回收(如果可能)
      if (window.gc) {
        window.gc();
      }

      // 重新检查内存
      const newUsage = await this.checkMemoryUsage();
      return (file.size * 3) < (newUsage.limit - newUsage.used);
    }

    return true;
  }

  // 流式处理大文件
  async processLargeFileInChunks(
    file: File,
    processor: (chunk: Uint8Array) => Promise<void>,
    chunkSize = 1024 * 1024 // 1MB
  ): Promise<void> {
    const reader = new FileReader();
    let offset = 0;

    const processChunk = () => {
      if (offset >= file.size) {
        return Promise.resolve();
      }

      return new Promise<void>((resolve, reject) => {
        const chunk = file.slice(offset, offset + chunkSize);

        reader.onload = async (event) => {
          try {
            if (event.target?.result) {
              const arrayBuffer = event.target.result as ArrayBuffer;
              const uint8Array = new Uint8Array(arrayBuffer);

              await processor(uint8Array);
              offset += chunkSize;

              // 检查内存使用
              const memoryUsage = await this.checkMemoryUsage();
              if (memoryUsage.usageRatio > 0.8) {
                console.warn('High memory usage, forcing garbage collection');
                if (window.gc) window.gc();
              }

              await processChunk();
            }
            resolve();
          } catch (error) {
            reject(error);
          }
        };

        reader.onerror = () => reject(new Error('File reading failed'));
        reader.readAsArrayBuffer(chunk);
      });
    };

    return processChunk();
  }
}`
        }
      ],
      prevention: [
        '实施浏览器兼容性检查',
        '监控内存使用',
        '提供降级方案',
        '实施优雅错误处理'
      ]
    };
  }
}

使用方法

上传错误诊断

skill: "walrus-debugger"
// error-type: upload
// error-context: Upload failed: insufficient storage balance, trying to upload 10MB file to testnet
// environment: browser

网络连接问题

skill: "walrus-debugger"
// error-type: network
// error-context: Network timeout when connecting to storage nodes, intermittent connection issues
// environment: production

配置验证

skill: "walrus-debugger"
// error-type: configuration
// error-context: WASM module failed to load in Vite production build, error: "Failed to resolve module"
// environment: nodejs

性能问题

skill: "walrus-debugger"
// error-type: performance
// error-context: Memory usage spikes when uploading multiple large files, browser crashes
// environment: browser

更新时间2025-11-11