RGB 客戶端驗證詳解

理解 RGB 如何實現客戶端驗證與狀態膨脹控制。

RGB 客戶端驗證完整技術指南:深度分析與實作

RGB 是建構在比特幣區塊鏈上的智慧合約協議,採用革命性的「客戶端驗證」範式實現擴容與隱私保護。理解 RGB 的客戶端驗證機制對於正確設計資料流、開發應用程式以及確保資產安全至關重要。本文從密碼學基礎到實際程式碼,全面解析 RGB 客戶端驗證的運作原理與實作要點。

RGB 協議架構基礎

客戶端驗證範式

傳統區塊鏈(如以太坊)採用「全域狀態」模型:所有節點都儲存並驗證整個網路的狀態。這種設計雖然簡單,但面臨狀態膨脹、隱私泄漏和擴展性受限的問題。RGB 採用完全不同的「客戶端驗證」範式,只讓涉及的參與者驗證相關狀態轉移。

RGB vs 傳統區塊鏈驗證模型:

傳統區塊鏈(全節點驗證):
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   ┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐ │
│   │ Node A  │────▶│ Node B  │────▶│ Node C  │────▶│ Node D  │ │
│   └─────────┘     └─────────┘     └─────────┘     └─────────┘ │
│       │               │               │               │         │
│       ▼               ▼               ▼               ▼         │
│   ┌─────────────────────────────────────────────────────────────┐│
│   │              完整狀態副本(每個節點)                       ││
│   │  - 所有帳戶餘額                                            ││
│   │  - 所有合約狀態                                            ││
│   │  - 所有交易歷史                                            ││
│   └─────────────────────────────────────────────────────────────┘│
│                                                                 │
│   問題:                                                       │
│   • 狀態線性增長                                               │
│   • 所有數據對所有節點可見                                      │
│   • 驗證負載隨網路擴展                                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RGB(客戶端驗證):
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   ┌──────────────┐         ┌──────────────┐                   │
│   │  Alice       │◀──────▶│  Bob         │                   │
│   │  Client      │         │  Client      │                   │
│   └──────────────┘         └──────────────┘                   │
│         │                          │                            │
│         ▼                          ▼                            │
│   ┌─────────────────────────────────────────────────────────────┐│
│   │              客戶端本地狀態                                  ││
│   │  - 僅保存 Alice 涉及的 UTXO                                ││
│   │  - 僅保存 Alice 涉及的狀態轉移                              ││
│   │  - 透過密碼學證明驗證                                       ││
│   └─────────────────────────────────────────────────────────────┘│
│                                                                 │
│   優勢:                                                       │
│   • 狀態不上鏈,無膨脹問題                                     │
│   • 數據只在參與者之間共享                                      │
│   • 驗證負載分散到各客戶端                                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RGB 與比特幣的關係

RGB 並非獨立的區塊鏈,而是利用比特幣 UTXO 模型的第二層協議。RGB 的狀態承諾透過比特幣腳本嵌入,而實際的狀態數據存儲在鏈下。

RGB 比特幣架構:

比特幣 Layer 1:
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   TXID: abc123...                                              │
│   ├── Input 0: UTXO #1 (RGB 狀態承諾)                          │
│   │   └── OP_RETURN <commitment>                               │
│   │                                                             │
│   └── Output 0: UTXO #2                                         │
│       └── P2WSH: <witness script>                              │
│           └── 轉移給下一個所有者                                │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RGB Layer 2:
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   鏈下數據(客戶端):                                          │
│   ├── Genesis: 發行新資產                                        │
│   │   └── schema: RGB20 (fungible) / RGB21 (semi-fungible)    │
│   │   └── metadata: 名稱、供應量、精度                          │
│   │   └── initial UTXO set                                     │
│   │                                                             │
│   ├── Transfer: 狀態轉移                                        │
│   │   └── input: 前一 UTXO 的 commitment                       │
│   │   └── output: 新 UTXO 設定                                 │
│   │   └── witness: 密碼學證明                                   │
│   │                                                             │
│   └── Consignment: 交付                                         │
│       └── state transition proof                                │
│       └── transition artifact                                  │
│       └── witness data                                         │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RGB 核心概念詳解

資產類型(RGB20 / RGB21 / RGB25)

RGB 協議定義了多種資產標準,適用於不同的用例:

RGB 資產標準對比:

┌────────────────┬────────────────────────────────────────────────┐
│ 標準           │ 用途與特性                                    │
├────────────────┼────────────────────────────────────────────────┤
│ RGB20          │ 同質化代幣(Fungible Tokens)                 │
│                │ • 類似 ERC-20                                  │
│                │ • 適用:貨幣、股份、積分                        │
│                │ • 屬性:供應量、精度、轉讓權                   │
├────────────────┼────────────────────────────────────────────────┤
│ RGB21          │ 非同質化代幣(NFT)                           │
│                │ • 類似 ERC-721                                 │
│                │ • 適用:藝術品、收藏品、門票                    │
│                │ • 屬性:元數據、媒體內容                        │
├────────────────┼────────────────────────────────────────────────┤
│ RGB22          │ 同質化 NFT(集合)                            │
│                │ • 同質化但可追蹤                               │
│                │ • 適用:票務、藝術家代幣                        │
├────────────────┼────────────────────────────────────────────────┤
│ RGB25          │ 染色幣擴展                                    │
│                │ • 向後兼容染色幣                                │
│                │ • 遷移路徑                                     │
└────────────────┴────────────────────────────────────────────────┘

RGB20 範例結構:

{

"schema": "RGB20",

"name": "Bitcoin Stablecoin",

"symbol": "BTCS",

"decimals": 8,

"supply": 1000000000000,

"issuer": "7f4cc2...",

"primal": "rgb20://7f4cc2.../issue1"

}

狀態轉移與證明

RGB 的核心創新是將狀態轉移與比特幣交易綁定。每個狀態轉移都需要攜帶可驗證的密碼學證明。

RGB 狀態轉移機制:

簡單轉移流程(Alice → Bob):

步驟 1: 準備輸出
┌─────────────────────────────────────────────────────────────────┐
│ Alice 準備轉移給 Bob:                                          │
│ • 選擇要轉移的 UTXO(假設價值 100 RGB20)                       │
│ • 設定輸出條件(例如:只有 Bob 的公鑰 可以解鎖)                 │
│ • 生成狀態轉移 commitment                                        │
└─────────────────────────────────────────────────────────────────┘
    │
    ▼
步驟 2: 創建比特幣交易
┌─────────────────────────────────────────────────────────────────┐
│ Alice 創建比特幣交易:                                           │
│ • 花費包含 RGB commitment 的 UTXO                                │
│ • 創建新的輸出(包含給 Bob 的 RGB 狀態)                         │
│ •  Commitment 包含在 OP_RETURN 或見證數據中                      │
└─────────────────────────────────────────────────────────────────┘
    │
    ▼
步驟 3: 生成轉移證明
┌─────────────────────────────────────────────────────────────────┐
│ Alice 生成轉移證明:                                              │
│ • 狀態轉移描述(誰轉給誰,多少)                                 │
│ • 前一 UTXO 的驗證證明                                           │
│ • 資產所有權證明                                                 │
│ • 輸出綁定承諾                                                  │
└─────────────────────────────────────────────────────────────────┘
    │
    ▼
步驟 4: 交付給 Bob
┌─────────────────────────────────────────────────────────────────┐
│ Alice 交付 consignment 給 Bob:                                   │
│ • 狀態轉移證明                                                   │
│ • 所有相關的歷史證明                                             │
│ • 完整的轉移上下文                                               │
└─────────────────────────────────────────────────────────────────┘
    │
    ▼
步驟 5: Bob 驗證
┌─────────────────────────────────────────────────────────────────┐
│ Bob 驗證收到的 consignment:                                      │
│ • 驗證比特幣交易存在且確認                                       │
│ • 驗證 commitment 正確                                          │
│ • 驗證所有前向證明鏈                                            │
│ • 驗證簽名有效性                                                 │
│ • 驗證無雙重支付                                                 │
│                                                                 │
│ 驗證通過後,Bob 接受新狀態                                       │
└─────────────────────────────────────────────────────────────────┘

客戶端驗證深度技術分析

驗證層級架構

RGB 的客戶端驗證涉及多個層次的檢查,每個層次都有其特定的目的和機制:

RGB 客戶端驗證架構:

┌─────────────────────────────────────────────────────────────────┐
│                      第五層:業務邏輯驗證                         │
├─────────────────────────────────────────────────────────────────┤
│  • 資產規則驗證(轉移數量不超過可用餘額)                         │
│  • 權限驗證(轉讓權限正確)                                      │
│  • 狀態轉移有效性                                                │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      第四層:比特幣驗證                          │
├─────────────────────────────────────────────────────────────────┤
│  • 區塊確認數量足夠                                              │
│  • 交易格式正確                                                  │
│  • 區塊鏈重組保護                                                │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      第三層:承諾驗證                            │
├─────────────────────────────────────────────────────────────────┤
│  • UTXO  commitment 正確                                         │
│  • 輸出綁定驗證                                                  │
│  • 狀態 commitment 正確                                          │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      第二層:所有權驗證                         │
├─────────────────────────────────────────────────────────────────┤
│  • 簽名驗證(ECDSA / Schnorr)                                   │
│  • 密鑰所有權證明                                                │
│  • 授權轉移驗證                                                  │
└─────────────────────────────────────────────────────────────────┘
                              │
                              ▼
┌─────────────────────────────────────────────────────────────────┐
│                      第一層:數據完整性驗證                     │
├─────────────────────────────────────────────────────────────────┤
│  • 轉移數據格式正確                                              │
│  • JSON schema 驗證                                             │
│  • 證明結構完整                                                  │
└─────────────────────────────────────────────────────────────────┘

驗證實作程式碼

以下是 RGB 客戶端驗證的完整實作範例:

// rgb-validator.ts

import {
  Transaction,
  OutPoint,

  validateTransition,
  verifySignature,
  verifyProof,
  Commitment
} from 'rgb-core';

// 驗證結果類型
interface ValidationResult {
  valid: boolean;
  errors: ValidationError[];
  warnings: ValidationWarning[];
}

interface ValidationError {
  layer: number;
  code: string;
  message: string;
  details?: any;
}

interface ValidationWarning {
  layer: number;
  code: string;
  message: string;
}

// RGB20 轉移驗證器
export class RGB20TransferValidator {

  /**
   * 驗證完整的 RGB20 轉移
   */
  async validateTransfer(
    consignment: Consignment,
    currentState: RGB20State
  ): Promise<ValidationResult> {
    const errors: ValidationError[] = [];
    const warnings: ValidationWarning[] = [];

    try {
      // 第一層:數據完整性
      this.validateDataIntegrity(consignment);
    } catch (e) {
      errors.push({
        layer: 1,
        code: 'INVALID_FORMAT',
        message: 'Consignment format invalid',
        details: e
      });
    }

    try {
      // 第二層:所有權驗證
      await this.validateOwnership(consignment, currentState);
    } catch (e) {
      errors.push({
        layer: 2,
        code: 'INVALID_OWNERSHIP',
        message: 'Ownership verification failed',
        details: e
      });
    }

    try {
      // 第三層:承諾驗證
      this.validateCommitments(consignment);
    } catch (e) {
      errors.push({
        layer: 3,
        code: 'INVALID_COMMITMENT',
        message: 'Commitment verification failed',
        details: e
      });
    }

    try {
      // 第四層:比特幣驗證
      await this.validateBitcoin(consignment);
    } catch (e) {
      errors.push({
        layer: 4,
        code: 'INVALID_BITCOIN',
        message: 'Bitcoin verification failed',
        details: e
      });
    }

    try {
      // 第五層:業務邏輯驗證
      this.validateBusinessLogic(consignment, currentState);
    } catch (e) {
      errors.push({
        layer: 5,
        code: 'INVALID_LOGIC',
        message: 'Business logic verification failed',
        details: e
      });
    }

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

  /**
   * 第一層:數據完整性驗證
   */
  private validateDataIntegrity(consignment: Consignment): void {
    // 檢查必要欄位
    if (!consignment.version) {
      throw new Error('Missing version');
    }

    if (!consignment.transitions || consignment.transitions.length === 0) {
      throw new Error('No transitions provided');
    }

    // 驗證每個轉移的結構
    for (const transition of consignment.transitions) {
      if (!transition.id) {
        throw new Error('Transition missing ID');
      }

      if (!transition.inputs || transition.inputs.length === 0) {
        throw new Error('Transition has no inputs');
      }

      if (!transition.outputs || transition.outputs.length === 0) {
        throw new Error('Transition has no outputs');
      }

      // 驗證輸出定義
      for (const output of transition.outputs) {
        if (!output.script) {
          throw new Error('Output missing script');
        }

        if (!output.blinding) {
          throw new Error('Output missing blinding factor');
        }
      }

      // 驗證 witness 數據
      if (!transition.witness) {
        throw new Error('Transition missing witness');
      }
    }

    // 驗證 proof 結構
    for (const proof of consignment.proofs) {
      if (!proof.outpoint) {
        throw new Error('Proof missing outpoint');
      }

      if (!proof.authenticityProof) {
        throw new Error('Proof missing authenticity proof');
      }
    }
  }

  /**
   * 第二層:所有權驗證
   */
  private async validateOwnership(
    consignment: Consignment,
    currentState: RGB20State
  ): Promise<void> {
    const prevStates = new Map<string, State>();

    // 重建每個輸入的先前狀態
    for (const transition of consignment.transitions) {
      for (const input of transition.inputs) {
        const prevState = prevStates.get(input.prevOutpoint);

        if (!prevState) {
          // 查找當前狀態
          const currentUTXO = currentState.utxos.find(
            u => u.outpoint === input.prevOutpoint
          );

          if (!currentUTXO) {
            throw new Error(`Input UTXO not found: ${input.prevOutpoint}`);
          }

          // 驗證簽名
          const valid = verifySignature(
            input.witness,
            currentUTXO.ownerPublicKey,
            transition
          );

          if (!valid) {
            throw new Error(`Signature verification failed for input: ${input.prevOutpoint}`);
          }
        }
      }
    }
  }

  /**
   * 第三層:承諾驗證
   */
  private validateCommitments(consignment: Consignment): void {
    for (const transition of consignment.transitions) {
      // 驗證轉移 commitment
      const computedCommitment = this.computeCommitment(transition);

      if (computedCommitment !== transition.commitment) {
        throw new Error('Transition commitment mismatch');
      }

      // 驗證輸出綁定
      for (const output of transition.outputs) {
        const bindingValid = this.verifyOutputBinding(
          output,
          transition.commitment
        );

        if (!bindingValid) {
          throw new Error('Output binding verification failed');
        }
      }
    }
  }

  /**
   * 第四層:比特幣區塊鏈驗證
   */
  private async validateBitcoin(consignment: Consignment): Promise<void> {
    const confirmationsRequired = 6; // 可配置

    for (const proof of consignment.proofs) {
      // 驗證比特幣交易存在
      const txExists = await this.checkBitcoinTransaction(proof.outpoint.txid);

      if (!txExists) {
        throw new Error(`Bitcoin transaction not found: ${proof.outpoint.txid}`);
      }

      // 驗證確認數
      const confirmations = await this.getConfirmations(proof.outpoint.txid);

      if (confirmations < confirmationsRequired) {
        throw new Error(
          `Insufficient confirmations: ${confirmations} < ${confirmationsRequired}`
        );
      }

      // 驗證交易輸出正確
      const outputValid = await this.verifyBitcoinOutput(proof.outpoint);

      if (!outputValid) {
        throw new Error(`Bitcoin output verification failed: ${proof.outpoint}`);
      }
    }
  }

  /**
   * 第五層:業務邏輯驗證
   */
  private validateBusinessLogic(
    consignment: Consignment,
    currentState: RGB20State
  ): void {
    // 計算轉入和轉出
    let totalIn = 0n;
    let totalOut = 0n;

    for (const transition of consignment.transitions) {
      // 輸入價值
      for (const input of transition.inputs) {
        const inputUTXO = currentState.utxos.find(
          u => u.outpoint === input.prevOutpoint
        );

        if (inputUTXO) {
          totalIn += inputUTXO.amount;
        }
      }

      // 輸出價值
      for (const output of transition.outputs) {
        totalOut += output.amount;
      }
    }

    // 驗證轉移不超過可用餘額
    if (totalOut > totalIn) {
      throw new Error(
        `Transfer exceeds input: ${totalOut} > ${totalIn}`
      );
    }

    // 驗證沒有負值轉移
    if (totalIn < 0 || totalOut < 0) {
      throw new Error('Negative transfer value detected');
    }

    // 驗證精度匹配
    for (const transition of consignment.transions) {
      for (const output of transition.outputs) {
        if (!this.isValidPrecision(output.amount, currentState.decimals)) {
          throw new Error(
            `Invalid precision for amount: ${output.amount}`
          );
        }
      }
    }
  }

  // 輔助方法
  private computeCommitment(transition: Transition): Commitment {
    // 實現 commitment 計算
    return {} as Commitment;
  }

  private verifyOutputBinding(output: Output, commitment: Commitment): boolean {
    // 實現輸出綁定驗證
    return true;
  }

  private async checkBitcoinTransaction(txid: string): Promise<boolean> {
    // 實現比特幣交易檢查
    return true;
  }

  private async getConfirmations(txid: string): Promise<number> {
    // 實現確認數獲取
    return 10;
  }

  private async verifyBitcoinOutput(outpoint: OutPoint): Promise<boolean> {
    // 實現比特幣輸出驗證
    return true;
  }

  private isValidPrecision(amount: bigint, decimals: number): boolean {
    // 驗證精度
    const divisor = 10n ** BigInt(decimals);
    return amount % divisor === 0nn;
  }
}

資料可用性挑戰

客戶端驗證最大的工程挑戰是資料可用性。由於狀態數據存儲在鏈下,必須確保轉移的接收方能夠獲得完整的歷史證明。

RGB 資料可用性解決方案:

挑戰說明:
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│   Alice ──轉移──▶ Bob                                           │
│       │                                                          │
│       │ 問題:如果 Alice 丟失數據,Bob 如何驗證?                 │
│       │                                                          │
│       ▼                                                          │
│   Bob 需要:                                                     │
│   ├── 完整的轉移歷史                                             │
│   ├── 所有先前狀態的證明                                         │
│   └── 資產有效性的密碼學證明                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

解決方案比較:

方案 1:直接交付
┌─────────────────────────────────────────────────────────────────┐
│  描述:Alice 直接將 consignment 交付給 Bob                      │
│                                                                 │
│  優點:                                                          │
│  • 簡單直接                                                     │
│  • 不依賴第三方                                                 │
│                                                                 │
│  缺點:                                                          │
│  • 雙方必須同時在線                                             │
│  • 如果長期不接觸可能遺失數據                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

方案 2:第三方存儲
┌─────────────────────────────────────────────────────────────────┐
│  描述:使用專門的儲存服務(如 IPFS、雲存儲)                     │
│                                                                 │
│  優點:                                                          │
│  • 隨時可訪問                                                  │
│  • 可選擇多個存儲提供者                                          │
│                                                                 │
│  缺點:                                                          │
│  • 引入第三方信任假設                                           │
│  • 需要選擇可靠的存儲服務                                        │
│  • 可能的隱私問題                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

方案 3:SPD(Single Use Seals)
┌─────────────────────────────────────────────────────────────────┐
│  描述:使用一次性密封件確保數據完整性                            │
│                                                                 │
│  機制:                                                         │
│  • 每個轉移創建一個「密封件」                                    │
│  • 只有打開當前密封件才能創建新密封件                            │
│  • 確保歷史不可篡改                                              │
│                                                                 │
│  優點:                                                          │
│  • 數學上可證明的完整性                                         │
│  • 不需要長期存儲                                               │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

方案 4:分布式存儲 + 驗證
┌─────────────────────────────────────────────────────────────────┐
│  描述:使用分布式存儲 + 客戶端交叉驗證                           │
│                                                                 │
│  實現:                                                         │
│  • 多個客戶端互相備份                                            │
│  • 定期驗證數據完整性                                           │
│  • 激勵節點提供存儲                                             │
│                                                                 │
│  優點:                                                          │
│  • 去中心化                                                     │
│  • 激勵相容                                                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

RGB 錢包開發指南

###錢包架構設計

開發 RGB 錢包需要理解其獨特的狀態管理需求。以下是錢包架構的詳細設計:

// rgb-wallet.ts

import {
  DerivationPath,
  KeyDerivation,
  createWallet,
  UTXO,
  State,
  Consignment
} from 'rgb-core';
import { createTransport, Transport } from '@rgb-sdk/transport';

// 錢包配置
interface RGBWalletConfig {
  network: 'bitcoin' | 'bitcoin_testnet' | 'regtest';
  derivationPath: string;
  chainBackend: string;
  storageBackend: string;
}

// RGB 錢包類
export class RGBWallet {
  private config: RGBWalletConfig;
  private keyManager: KeyDerivation;
  private state: WalletState;
  private transport: Transport;

  constructor(config: RGBWalletConfig) {
    this.config = config;
    this.state = new WalletState();
  }

  /**
   * 初始化錢包
   */
  async initialize(mnemonic: string): Promise<void> {
    // 初始化密鑰管理
    this.keyManager = new KeyDerivation({
      mnemonic,
      network: this.config.network,
      path: this.config.derivationPath
    });

    // 初始化傳輸層
    this.transport = createTransport({
      backend: this.config.chainBackend
    });

    // 加載錢包狀態
    await this.loadState();

    // 同步比特幣 UTXO
    await this.syncUTXOs();

    // 同步 RGB 狀態
    await this.syncRGBState();
  }

  /**
   * 獲取錢包比特幣地址
   */
  getAddress(type: 'pkh' | 'wpkh' | 'tr'): string {
    return this.keyManager.getAddress(type);
  }

  /**
   * 查詢資產餘額
   */
  async getBalance(assetId: string): Promise<AssetBalance> {
    const rgbState = this.state.rgbStates.get(assetId);

    if (!rgbState) {
      return { available: 0n, locked: 0n };
    }

    // 計算可用餘額(未花費的輸出)
    let available = 0n;
    let locked = 0n;

    for (const utxo of rgbState.utxos) {
      if (utxo.spent) {
        locked += utxo.amount;
      } else {
        available += utxo.amount;
      }
    }

    return { available, locked };
  }

  /**
   * 創建轉移交易
   */
  async createTransfer(
    assetId: string,
    recipient: string,
    amount: bigint,
    fee?: bigint
  ): Promise<UnsignedTransfer> {
    // 獲取可用 UTXO
    const availableUTXOs = await this.getAvailableUTXOs(assetId);

    if (availableUTXOs.length === 0) {
      throw new Error('No available UTXOs');
    }

    // 選擇輸入 UTXO(簡單的 oldest-first 策略)
    const selectedUTXOs = this.selectUTXOs(availableUTXOs, amount);

    // 計算找零
    const totalInput = selectedUTXOs.reduce((sum, u) => sum + u.amount, 0n);
    const feeAmount = fee || await this.estimateFee(selectedUTXOs.length, 2);
    const changeAmount = totalInput - amount - feeAmount;

    // 創建轉移
    const transfer = {
      assetId,
      inputs: selectedUTXOs.map(u => ({
        outpoint: u.outpoint,
        witness: '' // 待填寫
      })),
      outputs: [
        {
          recipient,
          amount,
          blinding: this.generateBlinding(recipient, amount)
        }
      ],
      ...(changeAmount > 0n && {
        change: {
          address: this.getAddress('wpkh'),
          amount: changeAmount,
          blinding: this.generateBlinding(this.getAddress('wpkh'), changeAmount)
        }
      }),
      fee: feeAmount
    };

    return transfer;
  }

  /**
   * 簽名並廣播轉移
   */
  async signAndBroadcast(transfer: UnsignedTransfer): Promise<string> {
    // 簽名每個輸入
    const signedInputs = await Promise.all(
      transfer.inputs.map(async (input, index) => {
        const witness = await this.keyManager.sign({
          message: this.getSignMessage(transfer, index),
          derivationPath: `${this.config.derivationPath}/0/${index}`
        });

        return {
          ...input,
          witness
        };
      })
    );

    // 創建 consignment
    const consignment = await this.createConsignment({
      ...transfer,
      inputs: signedInputs
    });

    // 交付給接收方(在實際應用中,這由發送方處理)
    // 這裡我們廣播比特幣交易

    // 廣播比特幣交易
    const txid = await this.broadcastBitcoinTransaction(transfer);

    // 存儲轉移歷史
    await this.storeTransferHistory(transfer, txid, consignment);

    return txid;
  }

  /**
   * 導入 consignment(接收方使用)
   */
  async acceptConsignment(consignment: Consignment): Promise<void> {
    // 驗證 consignment
    const validator = new RGB20TransferValidator();
    const currentState = this.state.rgbStates.get(consignment.assetId);

    if (!currentState) {
      throw new Error('Asset state not found');
    }

    const result = await validator.validateTransfer(consignment, currentState);

    if (!result.valid) {
      throw new Error(
        `Validation failed: ${result.errors.map(e => e.message).join(', ')}`
      );
    }

    // 更新本地狀態
    this.updateState(consignment);

    // 存儲 consignment
    await this.storeConsignment(consignment);
  }

  // 輔助方法
  private async loadState(): Promise<void> {
    // 從存儲加載錢包狀態
  }

  private async syncUTXOs(): Promise<void> {
    // 同步比特幣 UTXO
    const address = this.getAddress('wpkh');
    const utxos = await this.transport.getUTXOs(address);

    this.state.btcUTXOs = utxos;
  }

  private async syncRGBState(): Promise<void> {
    // 同步 RGB 狀態
    for (const assetId of this.state.rgbAssets) {
      const rgbState = await this.fetchRGBState(assetId);
      this.state.rgbStates.set(assetId, rgbState);
    }
  }

  private selectUTXOs(utxos: RGBUTXO[], amount: bigint): RGBUTXO[] {
    const selected: RGBUTXO[] = [];
    let total = 0n;

    for (const utxo of utxos) {
      selected.push(utxo);
      total += utxo.amount;

      if (total >= amount) {
        break;
      }
    }

    if (total < amount) {
      throw new Error('Insufficient balance');
    }

    return selected;
  }

  private generateBlinding(recipient: string, amount: bigint): string {
    // 生成盲化因子
    return '';
  }

  private getSignMessage(transfer: UnsignedTransfer, inputIndex: number): string {
    // 創建簽名消息
    return '';
  }

  private async estimateFee(inputCount: number, outputCount: number): Promise<bigint> {
    // 估算費用
    return 1000n;
  }

  private async broadcastBitcoinTransaction(transfer: UnsignedTransfer): Promise<string> {
    // 廣播比特幣交易
    return '';
  }

  private async createConsignment(transfer: SignedTransfer): Promise<Consignment> {
    // 創建 consignment
    return {} as Consignment;
  }

  private updateState(consignment: Consignment): void {
    // 更新本地狀態
  }

  private async storeTransferHistory(
    transfer: UnsignedTransfer,
    txid: string,
    consignment: Consignment
  ): Promise<void> {
    // 存儲轉移歷史
  }

  private async storeConsignment(consignment: Consignment): Promise<void> {
    // 存儲 consignment
  }

  private async getAvailableUTXOs(assetId: string): Promise<RGBUTXO[]> {
    const state = this.state.rgbStates.get(assetId);
    return state?.utxos.filter(u => !u.spent) || [];
  }

  private async fetchRGBState(assetId: string): Promise<RGB20State> {
    // 獲取 RGB 狀態
    return {} as RGB20State;
  }
}

// 錢包狀態類
class WalletState {
  btcUTXOs: UTXO[] = [];
  rgbAssets: string[] = [];
  rgbStates: Map<string, RGB20State> = new Map();
  transferHistory: Transfer[] = [];
  consignments: Map<string, Consignment> = new Map();
}

安全性最佳實踐

常見錯誤與防範

在 RGB 開發和使⽤过程中,需要特别注意以下常見的安全性錯誤:

RGB 安全錯誤清單:

錯誤 1:驗證流程短路
┌─────────────────────────────────────────────────────────────────┐
│ 風險:跳過某些驗證層級可能導致接受無效的轉移                      │
│                                                                 │
│ 防範措施:                                                       │
│ • 始終執行完整的五層驗證                                         │
│ • 不要根據「可信」標記跳過驗證                                    │
│ • 記錄所有驗證結果                                              │
│ • 失敗時明確報告失敗層級                                        │
└─────────────────────────────────────────────────────────────────┘

錯誤 2:資料遺失
┌─────────────────────────────────────────────────────────────────┐
│ 風險:客戶端驗證模式下,數據遺失無法恢復                          │
│                                                                 │
│ 防範措施:                                                       │
│ • 實現多重備份策略                                               │
│ • 使用分布式存儲                                                 │
│ • 定期驗證數據完整性                                            │
│ • 建立數據恢復流程                                              │
└─────────────────────────────────────────────────────────────────┘

錯誤 3:版本不一致
┌─────────────────────────────────────────────────────────────────┐
│ 風險:不同客戶端版本可能導致狀態不兼容                           │
│                                                                 │
│ 防範措施:                                                       │
│ • 明確定義 schema 版本策略                                       │
│ • 實現向前向後兼容性                                              │
│ • 使用 migrations                                                │
│ • 升級前驗證                                                     │
└─────────────────────────────────────────────────────────────────┘

錯誤 4:盲化因子處理不當
┌─────────────────────────────────────────────────────────────────┐
│ 風險:盲化因子暴露導致隱私喪失                                   │
│                                                                 │
│ 防範措施:                                                       │
│ • 盲化因子只在客戶端內部使用                                     │
│ • 不通过网络傳輸                                                 │
│ • 每次轉移生成新的盲化因子                                       │
│ • 安全的內存管理                                                │
└─────────────────────────────────────────────────────────────────┘

多設備同步策略

RGB 錢包的多設備同步是實際應用中的重要需求:

多設備同步架構:

設計原則:
┌─────────────────────────────────────────────────────────────────┐
│                                                                 │
│  1. 事件溯源:所有狀態來自於事件歷史                              │
│  2. 衝突解決:明確的策略處理並發更新                             │
│  3. 增量同步:只同步變更而非完整狀態                             │
│  4. 端對端加密:敏感數據加密傳輸                                 │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

同步策略實現:

┌─────────────────────────────────────────────────────────────────┐
│ 事件溯源結構:                                                  │
│                                                                 │
│  interface StateEvent {                                         │
│    id: string;                                                   │
│    type: 'genesis' | 'transfer' | 'consignment';               │
│    timestamp: number;                                            │
│    data: any;                                                    │
│    proof: Proof;                                                 │
│  }                                                               │
│                                                                 │
│  同步流程:                                                      │
│                                                                 │
│  Device A                    Sync Server              Device B │
│     │                            │                          │ │
│     │───────Push Events────────▶│                          │ │
│     │                            │───────Push Events───────▶│ │
│     │                            │                          │ │
│     │◀───────Get New Events─────│                          │ │
│     │                            │◀─────Get New Events─────│ │
│     │                            │                          │ │
│     │──Validate Events──────────│                          │ │
│     │◀──Validation Result──────│                          │ │
│     │                            │──Validate Events────────│ │
│     │                            │◀─Validation Result─────│ │
│     │                            │                          │ │
└─────────────────────────────────────────────────────────────────┘

衝突解決策略:

策略 1:最後寫入 wins
┌─────────────────────────────────────────────────────────────────┐
│ • 簡單但可能丟失數據                                            │
│ • 基於時間戳或版本號                                            │
│ • 適合非關鍵數據                                                │
└─────────────────────────────────────────────────────────────────┘

策略 2:強制同步
┌─────────────────────────────────────────────────────────────────┐
│ • 需要完整重新同步                                               │
│ • 確保一致性                                                    │
│ • 適合重要操作(如餘額變更)                                     │
└─────────────────────────────────────────────────────────────────┘

策略 3:手動解決
┌─────────────────────────────────────────────────────────────────┐
│ • 提示用戶選擇                                                   │
│ • 顯示衝突選項                                                  │
│ • 用戶決定保留哪個                                              │
│ • 適合金額相關衝突                                              │
└─────────────────────────────────────────────────────────────────┘

RGB 與其他協議的比較

與以太坊的比較

RGB vs 以太坊:

┌────────────────┬────────────────────────┬────────────────────────┐
│ 特性           │ RGB                    │ 以太坊                 │
├────────────────┼────────────────────────┼────────────────────────┤
│ 區塊鏈         │ 比特幣                 │ 獨立                   │
├────────────────┼────────────────────────┼────────────────────────┤
│ 共識模型       │ 客戶端驗證             │ 全節點驗證             │
├────────────────┼────────────────────────┼────────────────────────┤
│ 隱私           │ 預設隱私               │ 需要額外協議           │
├────────────────┼────────────────────────┼────────────────────────┤
│ 狀態存儲       │ 鏈下                   │ 鏈上                   │
├────────────────┼────────────────────────┼────────────────────────┤
│ 擴展性         │ 高(客戶端分散)       │ 中等(EVM限制)        │
├────────────────┼────────────────────────┼────────────────────────┤
│ 開發難度       │ 高(概念新穎)         │ 中等(成熟工具)       │
├────────────────┼────────────────────────┼────────────────────────┤
│ 比特幣相容性   │ 完全相容               │ 不相容                 │
├────────────────┼────────────────────────┼────────────────────────┤
│ 智能合約       │ RGB++                  │ Solidity               │
└────────────────┴────────────────────────┴────────────────────────┘

結論

RGB 協議代表了一種全新的智慧合約範式,其客戶端驗證機制為比特幣帶來了圖靈完整的智慧合約能力,同時保持了比特幣的安全性與隱私特性。理解和正確實現客戶端驗證是開發 RGB 應用的核心挑戰。

關鍵要點回顧:

  1. 驗證層級:RGB 客戶端驗證涉及五個層次,從數據完整性到業務邏輯,每層都不可或缺。
  1. 資料可用性:這是 RGB 面臨的主要工程挑戰,需要合理的存儲和同步策略。
  1. 安全最佳實踐:完整的驗證流程、數據備份、版本管理是確保安全的基礎。
  1. 多設備同步:事件溯源和明確的衝突解決策略是實現可靠同步的關鍵。

RGB 仍在快速發展中,RGB20 和 RGB21 標準已趨於穩定,而 RGB++ 將帶來更強大的智慧合約能力。開發者應密切關注協議的演進,並根據最佳實踐構建安全、可靠的應用。


更新日期:2026-02-26

版本:1.0

延伸閱讀與來源

這篇文章對您有幫助嗎?

評論

發表評論

注意:由於這是靜態網站,您的評論將儲存在本地瀏覽器中,不會公開顯示。

目前尚無評論,成為第一個發表評論的人吧!