dApp Docs/AI Task L2执行层接入指南
Development reference. Not independently verified for production.

AI Task L2 执行层接入指南

MSG Chain 去中心化 AI 任务计算层

文档版本: v0.1.0 (规划态)
状态: X-L2-Planning=true
⚠️ No-Go Disclaimer: MSGChain 主网裁决为 No-Go。本文件所有内容反映的是开发阶段的技术设计,不代表主网未独立核验上线状态。生产部署状态请以白皮书为准:https://msgchain.org/whitepaper/


目录

  1. 概述
  2. 架构总览
  3. Task 生命周期
  4. Task 合约设计
  5. Off-chain Executor
  6. 证明与验证
  7. 经济模型
  8. 前端
  9. 路线图

1. 概述

1.1 什么是 AI Task L2

AI Task L2 是 MSG Chain 的去中心化 AI 任务执行层,采用 L1 结算 + L2 执行 的双层架构设计(类似 Arbitrum L2 的结算模式与 Akash 的计算市场模型的结合)。其核心思想是:

通过这种分离架构,AI 计算的执行成本不与 L1 区块空间竞争,同时 L1 的安全保证为计算结果提供最终确定性。

1.2 为什么需要 AI Task L2

需求 L1 原生限制 L2 方案优势
AI 推理执行 链上 gas 成本极高,无法运行大模型 离线执行,仅上链承诺与证明
执行时间 受限于区块时间(5s) 秒级到分钟级,无区块约束
计算资源 受限于验证者节点配置 可调度专用 GPU/TPU 节点
隐私保护 所有数据公开可见 TEE/ZK 证明可验证隐私计算
任务规模 单交易大小有限 支持大型输入/输出(MB~GB 级)

1.3 当前状态

Status: 规划态 (Planning Stage)
X-L2-Planning: true

已就绪基础组件:
  ├── Agent API 层        ── 未独立核验上线状态 (v1.0)
  ├── 交易收据系统         ── 已实现
  ├── 事件系统             ── 已实现
  ├── RPC 接口             ── 已实现
  ├── Agent 注册表         ── 已实现
  ├── 基金会金库           ── foundation_treasury_v2 (未独立核验上线状态)
  ├── DAO 治理             ── dao_governance_v1 (未独立核验上线状态)
  ├── AI Agent 宪法        ── ai_agent_constitution_v1 (未独立核验上线状态)
  └── Agent Payment 支付   ── agent_payment_v1 (未独立核验上线状态)

待实现组件 (全部标记 X-L2-Planning=true):
  ├── TaskManager 合约     ── 规划中
  ├── ReceiptRegistry 合约 ── 规划中
  ├── DisputeResolver 合约 ── 规划中
  ├── Settlement 合约      ── 规划中
  ├── Off-chain Executor   ── 规划中
  ├── Proof 证明系统       ── 规划中
  └── L1 Anchor 锚定机制   ── 规划中

1.4 核心概念


2. 架构总览

2.1 系统架构

┌──────────────────────────────────────────────────────────────────┐
│                        L1: MSG Chain 主链                        │
│                                                                   │
│  ┌──────────────────┐  ┌──────────────┐  ┌────────────────────┐ │
│  │  Settlement 合约   │  │  Governance   │  │    Treasury        │ │
│  │  (Settlement)      │  │  (DAO)        │  │    (金库)          │ │
│  │  X-L2-Planning     │  │  deployed    │  │   deployed         │ │
│  └────────┬─────────┘  └──────────────┘  └────────────────────┘ │
│           │                                                       │
│  ┌────────▼─────────┐  ┌──────────────┐  ┌────────────────────┐ │
│  │  TaskManager      │  │  ReceiptReg   │  │   DisputeResolver  │ │
│  │  X-L2-Planning    │  │  X-L2-Plan    │  │   X-L2-Planning    │ │
│  └────────┬─────────┘  └──────────────┘  └────────────────────┘ │
│           │                                                       │
│           └──────────────┬────────────────┘                       │
│                          │ L1 Anchor                              │
└──────────────────────────┼────────────────────────────────────────┘
                           │
                    Bridge Layer (桥接层)
                           │
┌──────────────────────────┼────────────────────────────────────────┐
│                          │  L2: AI Task 执行层                     │
│  ┌──────────────────┐    │                                        │
│  │  Off-chain        │◄───┘                                        │
│  │  Executor         │                                             │
│  │  (X-L2-Planning)  │                                             │
│  └────────┬─────────┘                                             │
│           │                                                       │
│  ┌────────▼─────────┐  ┌──────────────┐  ┌────────────────────┐ │
│  │  Worker 节点池     │  │  Proof Gen    │  │   TEE/Enclave     │ │
│  │  (GPU/CPU)        │  │  (ZK/TEE)     │  │   执行环境         │ │
│  └───────────────────┘  └──────────────┘  └────────────────────┘ │
│                                                                   │
│  ┌───────────────────┐  ┌──────────────┐                          │
│  │  Task Scheduler   │  │  Webhook      │                          │
│  │  (可选)           │  │  Notifier     │                          │
│  └───────────────────┘  └──────────────┘                          │
└──────────────────────────────────────────────────────────────────┘

2.2 核心流程

1. Submit Task ──► 2. Off-chain Execute ──► 3. Submit Receipt
       │                    │                        │
       ▼                    ▼                        ▼
  TaskManager         Worker 节点              ReceiptRegistry
       ▲                    ▲                        │
       │                    │                        ▼
 8. L1 Anchor ◄── 7. Settle ◄──── 6. Verify ◄── 5. Challenge
       │                    │                        │
       ▼                    ▼                        ▼
  L1 Finality         Settlement 合约          DisputeResolver

2.3 与 L1 现有合约的关系

AI Task L2 完全复用了 MSG Chain L1 现有基础设施:

L1 组件 合约 用途
DAO 治理 dao_governance_v1 L2 合约升级提案、参数投票
基金会金库 foundation_treasury_v2 Worker 奖励发放、Slashing 资金归集
Agent 支付 agent_payment_v1 基于里程碑的任务支付会话
AI Agent 宪法 ai_agent_constitution_v1 Worker 行为授权与合规检查
Agent API agent_v1 REST API 任务提交、状态查询接口

2.4 设计原则

  1. 最小信任假设:L2 执行结果必须可通过 L1 验证,无需信任任何第三方
  2. 阶段性最终性:optimistic 验证 + 挑战窗口,类似 Arbitrum 的挑战期设计
  3. 模块化合约:每个功能模块独立合约,通过 Dispatch 消息通信
  4. 经济安全:Worker 需要质押(bond),恶意行为将被 slashing
  5. 渐进式去中心化:从单 Worker 验证逐步过渡到多 Worker 共识验证

3. Task 生命周期

3.1 Task 定义

一个 Task 在系统中的完整定义如下:

// === X-L2-Planning=true ===
// 文件: contracts/ai-task-l2/src/msg.rs

use cosmwasm_std::Addr;
use serde::{Deserialize, Serialize};

/// Task 状态枚举
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum TaskStatus {
    Pending,        // 等待 Worker 接单
    Accepted,       // 已被 Worker 接受
    Executing,      // 执行中
    Completed,      // 执行完成,Receipt 已提交
    Challenged,     // 被质疑
    Disputed,       // 争议处理中
    Settled,        // 已结算
    Cancelled,      // 已取消
    Expired,        // 已过期
}

/// Task 数据结构
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Task {
    pub id: String,                       // 全局唯一 Task ID
    pub task_type: String,                // 任务类型 (inference/tool/orchestration)
    pub creator: Addr,                    // 任务创建者
    pub worker: Option<Addr>,             // 接单 Worker
    pub model_ref: String,               // AI 模型引用 (model_id or model_hash)
    pub model_hash: String,              // 模型 SHA3-256 哈希 (输入承诺)
    pub runtime_hash: String,            // 运行时环境哈希
    pub input_commitment: String,         // 输入数据承诺 (SHA3-256)
    pub output_commitment: Option<String>, // 输出数据承诺 (执行后设置)
    pub params: TaskParams,               // 执行参数
    pub reward: String,                   // 奖励金额 (u128 string)
    pub bond: String,                     // Worker 质押金额
    pub deadline: u64,                    // 截止时间戳 (unix seconds)
    pub challenge_window: u64,            // 挑战窗口时长 (seconds)
    pub status: TaskStatus,              // 当前状态
    pub created_at: u64,                  // 创建时间戳
    pub updated_at: u64,                  // 最后更新时间戳
    pub metadata: Option<String>,         // 附加元数据 (JSON)
}

/// Task 执行参数
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TaskParams {
    pub max_gas: u64,                     // 最大 gas 消耗
    pub max_timeout: u64,                 // 最大执行时间 (seconds)
    pub input_format: String,             // 输入格式 (json/text/binary)
    pub output_format: String,            // 输出格式
    pub proof_required: bool,             // 是否需要 ZK 证明
    pub tee_required: bool,               // 是否需要 TEE 执行
    pub min_worker_reputation: u64,       // 最低 Worker 信誉分
    pub quorum_count: u64,                // 共识验证数量 (0=单 Worker)
}

/// 收据数据结构
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Receipt {
    pub task_id: String,                  // 对应 Task ID
    pub worker: Addr,                     // 执行 Worker
    pub output_commitment: String,        // 输出承诺 (SHA3-256)
    pub execution_proof: String,          // 执行证明 (proof_hash)
    pub runtime_hash: String,            // 运行时哈希
    pub output_uri: Option<String>,       // 输出数据 URI (IPFS/Arweave)
    pub gas_used: u64,                    // 实际 gas 消耗
    pub status: String,                   // 执行状态 (success/partial/failed)
    pub submitted_at: u64,               // 提交时间戳
    pub proof_level: String,             // 证明级别 (none/hash/zk/tee)
}

/// 挑战数据结构
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Challenge {
    pub id: String,                       // 挑战 ID
    pub task_id: String,                  // 被质疑的 Task ID
    pub challenger: Addr,                 // 挑战者
    pub reason: String,                   // 质疑原因
    pub proof_hash: String,              // 反证哈希
    pub status: ChallengeStatus,         // 挑战状态
    pub created_at: u64,
    pub resolved_at: Option<u64>,
}

#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
pub enum ChallengeStatus {
    Open,         // 等待响应
    Responded,    // Worker 已回应
    Resolved,     // 已解决
    Expired,      // 过期
}

3.2 Task 提交流程

Task 提交可以通过两种方式:

方式 A:通过 L1 CosmWasm 合约提交

// === X-L2-Planning=true ===
// 合约提交 Task 的 ExecuteMsg

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum ExecuteMsg {
    SubmitTask {
        task: Task,
        deposit: String,    // 押金 + 奖励
    },
    AcceptTask {
        task_id: String,
        bond: String,       // Worker 质押
    },
    SubmitReceipt {
        task_id: String,
        receipt: Receipt,
    },
    ChallengeTask {
        task_id: String,
        reason: String,
        deposit: String,    // 挑战押金
    },
    RespondChallenge {
        task_id: String,
        challenge_id: String,
        evidence: String,   // 反证数据哈希
    },
    SettleTask {
        task_id: String,
    },
    CancelTask {
        task_id: String,
    },
}

方式 B:通过 Agent API 提交(建议)

利用未独立核验上线状态的 Agent API 接口提交任务:

// Agent API Task 提交示例
// POST /agent/v1/work/tasks/offer

const taskOfferPayload = {
  work_id: "task-001",
  call_chain_id: "ai-l2-call-chain-001",
  capability_ref: "ai-inference-v1",
  task_ref: "llm-inference-task",
  service_terms_hash: "abc123...",
  price_asset: "uom",
  price_amount: "1000000",
  budget_id: "budget-001",
  escrow_id: "escrow-001",
  escrow_lock_hash: "def456...",
  provider_requirements_hash: "ghi789...",
  metadata_hash: "jkl012..."
};

// 实际请求
const response = await fetch("https://node.msgchain.io/agent/v1/work/tasks/offer", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "your-api-key"
  },
  body: JSON.stringify(taskOfferPayload)
});

3.3 Task 状态机

                        ┌──────────┐
                        │  Pending  │◄──── SubmitTask
                        └────┬─────┘
                             │ AcceptTask
                             ▼
                        ┌──────────┐
                   ┌───►│ Accepted │
                   │    └────┬─────┘
                   │         │ Worker 开始执行
                   │         ▼
                   │    ┌───────────┐
                   │    │ Executing │
                   │    └────┬──────┘
                   │         │ SubmitReceipt
                   │         ▼
                   │    ┌───────────┐
                   │    │ Completed │
                   │    └────┬──────┘
                   │         │
              ┌────┴────┐    │
              │         │    │
              ▼         │    ▼
        ┌─────────┐     │  ┌─────────┐
        │Expired  │     │  │Settled  │◄── Final
        └─────────┘     │  └─────────┘
                        │
                   ┌────┘
                   ▼
             ┌───────────┐
             │Challenged │
             └─────┬─────┘
                   │ RespondChallenge
                   ▼
             ┌──────────┐
             │ Disputed │
             └─────┬────┘
                   │ Resolve
                   ▼
             ┌──────────┐
             │ Settled  │── 或 ──► Slashed
             └──────────┘

3.4 完整生命周期示例

// === X-L2-Planning=true ===
// Task 完整生命周期 (TypeScript)

interface TaskLifecycleExample {
  // 1. 创建 Task
  async function createAndExecuteTask(): Promise<void> {
    // Step 1: 提交 Task
    const taskId = await submitTask({
      modelRef: "gpt4-model-v1",
      modelHash: sha256(input),
      inputCommitment: sha256(inputData),
      reward: "1000000uom",
      challengeWindow: 86400, // 24h
    });

    // Step 2: 查询 Task 状态
    let status = await queryTaskStatus(taskId);
    console.log("Task status:", status); // Pending

    // Step 3: Worker 接单 (由 Worker 节点调用)
    await acceptTask(taskId, { bond: "500000uom" });

    // Step 4: 获取输入数据 (从 IPFS/链上)
    const input = await fetchTaskInput(taskId);

    // Step 5: 执行 AI 推理 (off-chain)
    const output = await runInference(input);

    // Step 6: 提交 Receipt
    await submitReceipt(taskId, {
      outputCommitment: sha256(output),
      executionProof: generateProof(output),
      runtimeHash: runtimeEnvHash(),
      gasUsed: computeGasCost(),
      proofLevel: "tee",
    });

    // Step 7: 等待挑战窗口结束 (无挑战则自动结算)
    await waitForChallengeWindow(taskId);

    // Step 8: 结算
    await settleTask(taskId);

    // Step 9: 查询最终状态
    const finalStatus = await queryTaskStatus(taskId); // Settled
    console.log("Final status:", finalStatus);
  }
}

4. Task 合约设计

4.1 合约架构

CosmWasm 合约部署架构:

L1 MSG Chain
│
├── TaskManager.wasm         [X-L2-Planning=true]
│   ├── 状态: Task 存储
│   ├── Execute: submit/accept/cancel
│   └── Query: get_task/list_tasks
│
├── ReceiptRegistry.wasm     [X-L2-Planning=true]
│   ├── 状态: Receipt 存储
│   ├── Execute: submit_receipt
│   └── Query: get_receipt/list_receipts
│
├── DisputeResolver.wasm     [X-L2-Planning=true]
│   ├── 状态: Challenge/Dispute 存储
│   ├── Execute: challenge/respond/resolve
│   └── Query: get_challenge
│
├── Settlement.wasm          [X-L2-Planning=true]
│   ├── 状态: Settlement 记录
│   ├── Execute: settle/claim
│   └── Query: get_settlement
│
├── dao_governance_v1.wasm   [未独立核验上线状态]
│   └── 合约升级提案 / 参数治理
│
├── foundation_treasury_v2.wasm [未独立核验上线状态]
│   └── 奖励分发 / Slashing 归集
│
└── ai_agent_constitution_v1.wasm [未独立核验上线状态]
    └── Worker 行为授权检查

4.2 TaskManager 合约

// === X-L2-Planning=true ===
// 文件: contracts/ai-task-l2/src/contract.rs

use cosmwasm_std::{
    entry_point, to_json_binary, Addr, Binary, Coin, Deps, DepsMut, Env,
    MessageInfo, Order, Response, StdResult, Storage,
};
use cw_storage_plus::{Item, Map};

use crate::error::ContractError;
use crate::msg::{ExecuteMsg, InstantiateMsg, QueryMsg, TaskStatus};
use crate::state::{Config, Task};

// === 状态存储 ===

pub const CONFIG: Item<Config> = Item::new("config");
pub const TASKS: Map<&str, Task> = Map::new("tasks");
pub const TASK_COUNT: Item<u64> = Item::new("task_count");

// === 实例化 ===

#[entry_point]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> StdResult<Response> {
    let config = Config {
        admin: info.sender,
        treasury_contract: deps.api.addr_validate(&msg.treasury_contract)?,
        governance_contract: deps.api.addr_validate(&msg.governance_contract)?,
        min_bond: msg.min_bond,
        max_challenge_window: msg.max_challenge_window,
        protocol_fee_percent: msg.protocol_fee_percent,
        paused: false,
    };
    CONFIG.save(deps.storage, &config)?;
    TASK_COUNT.save(deps.storage, &0u64)?;
    Ok(Response::new()
        .add_attribute("method", "instantiate")
        .add_attribute("admin", info.sender))
}

// === 执行接口 ===

#[entry_point]
pub fn execute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::SubmitTask { task, deposit } => {
            execute_submit_task(deps, env, info, task, deposit)
        }
        ExecuteMsg::AcceptTask { task_id, bond } => {
            execute_accept_task(deps, env, info, task_id, bond)
        }
        ExecuteMsg::SubmitReceipt { task_id, receipt } => {
            execute_submit_receipt(deps, env, info, task_id, receipt)
        }
        ExecuteMsg::ChallengeTask { task_id, reason, deposit } => {
            execute_challenge_task(deps, env, info, task_id, reason, deposit)
        }
        ExecuteMsg::RespondChallenge { task_id, challenge_id, evidence } => {
            execute_respond_challenge(deps, env, info, task_id, challenge_id, evidence)
        }
        ExecuteMsg::SettleTask { task_id } => {
            execute_settle_task(deps, env, info, task_id)
        }
        ExecuteMsg::CancelTask { task_id } => {
            execute_cancel_task(deps, env, info, task_id)
        }
    }
}

// === 查询接口 ===

#[entry_point]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::GetTask { task_id } => {
            to_json_binary(&query_task(deps, task_id)?)
        }
        QueryMsg::ListTasks { start_after, limit } => {
            to_json_binary(&query_list_tasks(deps, start_after, limit)?)
        }
        QueryMsg::GetConfig {} => {
            to_json_binary(&CONFIG.load(deps.storage)?)
        }
        QueryMsg::GetTaskCount {} => {
            to_json_binary(&TASK_COUNT.load(deps.storage)?)
        }
        QueryMsg::ListTasksByStatus { status, start_after, limit } => {
            to_json_binary(&query_tasks_by_status(deps, status, start_after, limit)?)
        }
    }
}

4.3 TaskManager 核心逻辑

// === X-L2-Planning=true ===
// 文件: contracts/ai-task-l2/src/execution.rs

use cosmwasm_std::{Coin, DepsMut, Env, MessageInfo, Response, Storage, Uint128};
use crate::error::ContractError;
use crate::state::{Config, Task, TaskStatus, Receipt, Challenge, ChallengeStatus};
use crate::contract::{CONFIG, TASKS, TASK_COUNT};

/// 提交 Task
pub fn execute_submit_task(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    task: Task,
    deposit: Coin,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    if config.paused {
        return Err(ContractError::ContractPaused {});
    }

    // 验证押金
    let required_amount = task.reward.parse::<Uint128>()
        .map_err(|_| ContractError::InvalidAmount)?;
    if deposit.amount < required_amount {
        return Err(ContractError::InsufficientDeposit {});
    }

    // 生成 Task ID
    let count = TASK_COUNT.load(deps.storage)?;
    let task_id = format!("task-{}", count + 1);

    let new_task = Task {
        id: task_id.clone(),
        task_type: task.task_type,
        creator: info.sender.clone(),
        worker: None,
        model_ref: task.model_ref,
        model_hash: task.model_hash,
        runtime_hash: task.runtime_hash,
        input_commitment: task.input_commitment,
        output_commitment: None,
        params: task.params,
        reward: task.reward,
        bond: task.bond,
        deadline: env.block.time.seconds() + 3600, // 1h deadline
        challenge_window: task.challenge_window,
        status: TaskStatus::Pending,
        created_at: env.block.time.seconds(),
        updated_at: env.block.time.seconds(),
        metadata: task.metadata,
    };

    TASKS.save(deps.storage, &task_id, &new_task)?;
    TASK_COUNT.save(deps.storage, &(count + 1))?;

    Ok(Response::new()
        .add_attribute("action", "submit_task")
        .add_attribute("task_id", &task_id)
        .add_attribute("creator", info.sender)
        .add_attribute("reward", &task.reward))
}

/// Worker 接单
pub fn execute_accept_task(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    task_id: String,
    bond: Coin,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    let mut task = TASKS.load(deps.storage, &task_id)?;

    if task.status != TaskStatus::Pending {
        return Err(ContractError::InvalidStatus {});
    }
    if env.block.time.seconds() > task.deadline {
        task.status = TaskStatus::Expired;
        TASKS.save(deps.storage, &task_id, &task)?;
        return Err(ContractError::TaskExpired {});
    }

    let min_bond = Uint128::from(config.min_bond);
    if bond.amount < min_bond {
        return Err(ContractError::InsufficientBond {});
    }

    task.worker = Some(info.sender.clone());
    task.status = TaskStatus::Accepted;
    task.updated_at = env.block.time.seconds();
    TASKS.save(deps.storage, &task_id, &task)?;

    Ok(Response::new()
        .add_attribute("action", "accept_task")
        .add_attribute("task_id", &task_id)
        .add_attribute("worker", info.sender))
}

/// 提交 Receipt
pub fn execute_submit_receipt(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    task_id: String,
    receipt: Receipt,
) -> Result<Response, ContractError> {
    let mut task = TASKS.load(deps.storage, &task_id)?;

    if task.status != TaskStatus::Accepted
        && task.status != TaskStatus::Executing
    {
        return Err(ContractError::InvalidStatus {});
    }
    if task.worker.as_ref() != Some(&info.sender) {
        return Err(ContractError::Unauthorized {});
    }

    task.output_commitment = Some(receipt.output_commitment.clone());
    task.status = TaskStatus::Completed;
    task.updated_at = env.block.time.seconds();
    TASKS.save(deps.storage, &task_id, &task)?;

    // 存储 Receipt
    RECEIPTS.save(deps.storage, &task_id, &receipt)?;

    Ok(Response::new()
        .add_attribute("action", "submit_receipt")
        .add_attribute("task_id", &task_id)
        .add_attribute("worker", info.sender))
}

4.4 查询接口定义

// === X-L2-Planning=true ===
// 文件: contracts/ai-task-l2/src/msg.rs

use cosmwasm_std::Addr;
use serde::{Deserialize, Serialize};
use crate::state::{Receipt, Challenge, Task};

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct InstantiateMsg {
    pub treasury_contract: String,
    pub governance_contract: String,
    pub min_bond: u128,
    pub max_challenge_window: u64,
    pub protocol_fee_percent: u64,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum ExecuteMsg {
    SubmitTask {
        task: Task,
        deposit: Coin,
    },
    AcceptTask {
        task_id: String,
        bond: Coin,
    },
    SubmitReceipt {
        task_id: String,
        receipt: Receipt,
    },
    ChallengeTask {
        task_id: String,
        reason: String,
        deposit: Coin,
    },
    RespondChallenge {
        task_id: String,
        challenge_id: String,
        evidence: String,
    },
    SettleTask {
        task_id: String,
    },
    CancelTask {
        task_id: String,
    },
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub enum QueryMsg {
    GetTask {
        task_id: String,
    },
    ListTasks {
        start_after: Option<String>,
        limit: Option<u32>,
    },
    GetConfig {},
    GetTaskCount {},
    ListTasksByStatus {
        status: String,
        start_after: Option<String>,
        limit: Option<u32>,
    },
    GetReceipt {
        task_id: String,
    },
    GetChallenge {
        challenge_id: String,
    },
}

4.5 DisputeResolver 合约

// === X-L2-Planning=true ===
// 争议解决合约核心逻辑

/// 发起挑战
pub fn execute_challenge(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    task_id: String,
    reason: String,
    deposit: Coin,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    let task = TASKS.load(deps.storage, &task_id)?;

    // 仅在 Completed 状态才能被挑战
    if task.status != TaskStatus::Completed {
        return Err(ContractError::InvalidStatus {});
    }

    // 检查是否在挑战窗口内
    let challenge_deadline = task.receipt_submitted_at + task.challenge_window;
    if env.block.time.seconds() > challenge_deadline {
        return Err(ContractError::ChallengeWindowExpired {});
    }

    // 验证挑战押金 (押金 = task奖励 * 挑战费率)
    let challenge_fee = Uint128::from(config.challenge_fee_percent)
        * task_reward(task) / Uint128::new(100);
    if deposit.amount < challenge_fee {
        return Err(ContractError::InsufficientChallengeDeposit {});
    }

    let challenge_id = format!("challenge-{}", task_id);
    let challenge = Challenge {
        id: challenge_id.clone(),
        task_id: task_id.clone(),
        challenger: info.sender.clone(),
        reason,
        proof_hash: String::new(),
        status: ChallengeStatus::Open,
        created_at: env.block.time.seconds(),
        resolved_at: None,
    };

    CHALLENGES.save(deps.storage, &challenge_id, &challenge)?;

    let mut task = task.clone();
    task.status = TaskStatus::Challenged;
    TASKS.save(deps.storage, &task_id, &task)?;

    Ok(Response::new()
        .add_attribute("action", "challenge_task")
        .add_attribute("task_id", &task_id)
        .add_attribute("challenge_id", &challenge_id)
        .add_attribute("challenger", info.sender))
}

/// 裁决争议
pub fn execute_resolve_dispute(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    task_id: String,
    challenge_id: String,
    verdict: Verdict,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    // 仅允许 DAO / 仲裁者 调用
    if info.sender != config.arbitrator {
        return Err(ContractError::Unauthorized {});
    }

    let mut challenge = CHALLENGES.load(deps.storage, &challenge_id)?;
    let mut task = TASKS.load(deps.storage, &task_id)?;

    challenge.status = ChallengeStatus::Resolved;
    challenge.resolved_at = Some(env.block.time.seconds());
    CHALLENGES.save(deps.storage, &challenge_id, &challenge)?;

    match verdict {
        Verdict::WorkerValid => {
            task.status = TaskStatus::Completed;
            // 返还挑战者押金给 Worker (惩罚恶意挑战)
            // Worker 获得奖励
        }
        Verdict::ChallengerValid => {
            task.status = TaskStatus::Disputed;
            // Slash Worker 质押
            // 奖励挑战者
        }
        Verdict::Split => {
            task.status = TaskStatus::Settled;
            // 按比例分配
        }
    }

    TASKS.save(deps.storage, &task_id, &task)?;

    Ok(Response::new()
        .add_attribute("action", "resolve_dispute")
        .add_attribute("task_id", &task_id)
        .add_attribute("verdict", format!("{:?}", verdict)))
}

4.6 Settlement 合约

// === X-L2-Planning=true ===
// 结算合约核心逻辑

/// 结算 Task (挑战窗口过期后)
pub fn execute_settle(
    deps: DepsMut,
    env: Env,
    info: MessageInfo,
    task_id: String,
) -> Result<Response, ContractError> {
    let config = CONFIG.load(deps.storage)?;
    let mut task = TASKS.load(deps.storage, &task_id)?;

    match task.status {
        TaskStatus::Completed => {
            // 检查挑战窗口是否已过
            let settle_time = task.receipt_submitted_at + task.challenge_window;
            if env.block.time.seconds() < settle_time {
                return Err(ContractError::ChallengeWindowNotExpired {});
            }
        }
        TaskStatus::Challenged | TaskStatus::Disputed => {
            // 等待仲裁结果
            return Err(ContractError::DisputeInProgress {});
        }
        _ => return Err(ContractError::InvalidStatus {}),
    }

    // 计算费用
    let reward_amount = Uint128::from_str(&task.reward)?;
    let protocol_fee = reward_amount * Uint128::from(config.protocol_fee_percent) / Uint128::new(100);
    let worker_payment = reward_amount - protocol_fee;

    // 转移资金:
    //   1. Protocol fee -> Treasury
    //   2. Worker payment -> Worker
    //   3. Creator deposit -> unlock remaining
    task.status = TaskStatus::Settled;
    TASKS.save(deps.storage, &task_id, &task)?;

    Ok(Response::new()
        .add_attribute("action", "settle_task")
        .add_attribute("task_id", &task_id)
        .add_attribute("worker_payment", &worker_payment.to_string())
        .add_attribute("protocol_fee", &protocol_fee.to_string()))
}

4.7 合约部署流程

# === X-L2-Planning=true ===
# 部署流程 (规划)

# 1. 编译合约
cd contracts/ai-task-l2
cargo wasm
docker run --rm -v "$(pwd)":/code \
  --mount type=volume,source="$(basename "$(pwd)")_cache",target=/target \
  --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry \
  cosmwasm/rust-optimizer:0.15.0

# 2. 上传 WASM 到 MSG Chain
msgchain tx wasm store artifacts/ai_task_l2.wasm \
  --from admin --gas auto --gas-adjustment 1.3 \
  --chain-id msg-chain-1

# 3. 实例化合约
msgchain tx wasm instantiate <CODE_ID> \
  '{
    "treasury_contract": "msg1treasury...",
    "governance_contract": "msg1governance...",
    "min_bond": "500000000",
    "max_challenge_window": 86400,
    "protocol_fee_percent": 5
  }' \
  --label "ai-task-l2-manager" \
  --admin msg1admin... \
  --from admin --chain-id msg-chain-1

# 4. 查询合约
msgchain query wasm contract-state smart <CONTRACT_ADDR> \
  '{"get_config":{}}'

5. Off-chain Executor

5.1 架构设计

Off-chain Executor 是 AI Task L2 的执行引擎,负责:

  1. 监听 L1 上的 Task 事件
  2. 调度 Worker 节点执行任务
  3. 收集执行结果并生成 Receipt
  4. 将 Receipt 提交回 L1
  5. 通过 Webhook 通知任务完成
┌─────────────────────────────────────────────────────────┐
│                   Off-chain Executor                      │
│                                                           │
│  ┌────────────────────┐   ┌──────────────────────────┐   │
│  │   Event Watcher     │   │     Task Scheduler        │   │
│  │   (监听 L1 事件)    │──►│     (任务调度队列)         │   │
│  └────────────────────┘   └───────────┬──────────────┘   │
│                                       │                   │
│  ┌────────────────────┐   ┌───────────▼──────────────┐   │
│  │   Result Collector  │◄──│     Worker Pool           │   │
│  │   (收集执行结果)    │   │     (GPU/CPU 节点)        │   │
│  └────────────────────┘   └──────────────────────────┘   │
│                                       │                   │
│  ┌────────────────────┐   ┌───────────▼──────────────┐   │
│  │   Receipt Submit    │   │     Webhook Notifier      │   │
│  │   (提交收据到 L1)   │   │     (回调通知)            │   │
│  └────────────────────┘   └──────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

5.2 Executor 核心实现

// === X-L2-Planning=true ===
// 文件: executor/src/index.ts

import { EventEmitter } from "events";
import { CosmWasmClient, SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { calculateFee, GasPrice } from "@cosmjs/stargate";

// === 类型定义 ===

interface TaskOffer {
  workId: string;
  callChainId: string;
  capabilityRef: string;
  taskRef: string;
  serviceTermsHash: string;
  priceAmount: string;
  budgetId: string;
  escrowId: string;
  escrowLockHash: string;
}

interface ExecutionResult {
  taskId: string;
  output: string;
  outputHash: string;
  proofHash: string;
  gasUsed: number;
  status: "success" | "partial" | "failed";
}

interface ExecutorConfig {
  chainId: string;
  rpcEndpoint: string;
  mnemonic: string;
  contractAddress: string;
  gasPrice: string;
  workerId: string;
  maxConcurrent: number;
  pollInterval: number;
  webhookUrl?: string;
}

// === Executor 主类 ===

export class AIExecutor extends EventEmitter {
  private client!: CosmWasmClient;
  private signingClient!: SigningCosmWasmClient;
  private config: ExecutorConfig;
  private activeTasks: Map<string, AbortController> = new Map();
  private running = false;

  constructor(config: ExecutorConfig) {
    super();
    this.config = config;
  }

  // === 初始化 ===

  async initialize(): Promise<void> {
    const wallet = await DirectSecp256k1HdWallet.fromMnemonic(
      this.config.mnemonic,
      { prefix: "msg" }
    );

    this.client = await CosmWasmClient.connect(this.config.rpcEndpoint);

    const gasPrice = GasPrice.fromString(this.config.gasPrice);
    this.signingClient = await SigningCosmWasmClient.connectWithSigner(
      this.config.rpcEndpoint,
      wallet,
      { gasPrice }
    );

    console.log(`[Executor] Initialized worker: ${this.config.workerId}`);
    console.log(`[Executor] Chain ID: ${this.config.chainId}`);
    console.log(`[Executor] Contract: ${this.config.contractAddress}`);
  }

  // === 启动监听 ===

  async start(): Promise<void> {
    this.running = true;
    console.log("[Executor] Starting event watcher...");
    this.pollTasks();
  }

  async stop(): Promise<void> {
    this.running = false;
    for (const [taskId, controller] of this.activeTasks) {
      controller.abort();
    }
    this.activeTasks.clear();
    console.log("[Executor] Stopped.");
  }

  // === 轮询待处理任务 ===

  private async pollTasks(): Promise<void> {
    while (this.running) {
      try {
        const pendingTasks = await this.queryPendingTasks();

        for (const task of pendingTasks) {
          if (this.activeTasks.size >= this.config.maxConcurrent) {
            break;
          }
          if (!this.activeTasks.has(task.workId)) {
            this.executeTask(task).catch((err) => {
              console.error(`[Executor] Task ${task.workId} failed:`, err);
            });
          }
        }
      } catch (err) {
        console.error("[Executor] Poll error:", err);
      }

      await new Promise((resolve) =>
        setTimeout(resolve, this.config.pollInterval)
      );
    }
  }

  // === 查询待处理任务 (通过 Agent API) ===

  private async queryPendingTasks(): Promise<TaskOffer[]> {
    // 使用未独立核验上线状态的 Agent API 查询待处理任务
    const response = await fetch(
      `${this.config.rpcEndpoint}/agent/v1/work/tasks/offer`,
      {
        method: "GET",
        headers: { "X-API-Key": process.env.AGENT_API_KEY || "" },
      }
    );

    const data = await response.json();
    return data.data?.pending_tasks || [];
  }

  // === 执行单个 Task ===

  private async executeTask(task: TaskOffer): Promise<void> {
    const controller = new AbortController();
    this.activeTasks.set(task.workId, controller);

    try {
      console.log(`[Executor] Accepting task: ${task.workId}`);

      // Step 1: 接受任务 (通过 Agent API)
      await this.acceptTask(task);

      // Step 2: 执行 AI 推理
      console.log(`[Executor] Executing task: ${task.workId}`);
      const result = await this.runInference(task, controller.signal);

      // Step 3: 生成证明
      const proof = await this.generateExecutionProof(result);

      // Step 4: 提交收据
      console.log(`[Executor] Submitting receipt for: ${task.workId}`);
      await this.submitReceipt(task.workId, result, proof);

      // Step 5: 通知回调
      if (this.config.webhookUrl) {
        await this.notifyWebhook(task.workId, result);
      }

      console.log(`[Executor] Task completed: ${task.workId}`);
      this.emit("taskCompleted", { taskId: task.workId, result });
    } catch (err: any) {
      if (err.name === "AbortError") {
        console.log(`[Executor] Task cancelled: ${task.workId}`);
      } else {
        console.error(`[Executor] Task error: ${task.workId}:`, err);
        this.emit("taskFailed", { taskId: task.workId, error: err.message });
      }
    } finally {
      this.activeTasks.delete(task.workId);
    }
  }

  // === 接受任务 (复用 Agent API) ===

  private async acceptTask(task: TaskOffer): Promise<void> {
    const response = await fetch(
      `${this.config.rpcEndpoint}/agent/v1/work/tasks/${task.workId}/accept`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-Key": process.env.AGENT_API_KEY || "",
        },
        body: JSON.stringify({
          provider_agent: this.config.workerId,
          provider_owner: process.env.WALLET_ADDRESS,
          acceptance_hash: crypto.createHash("sha256")
            .update(task.workId + Date.now())
            .digest("hex"),
          capability_proof_hash: task.serviceTermsHash,
        }),
      }
    );

    if (!response.ok) {
      throw new Error(`Accept task failed: ${response.statusText}`);
    }
  }

  // === AI 推理执行 (使用现有的 Agent Sandbox API) ===

  private async runInference(
    task: TaskOffer,
    signal: AbortSignal
  ): Promise<ExecutionResult> {
    // TODO: 实现实际的 AI 推理逻辑
    // 可使用现有的 agent_sandbox_api 沙箱执行环境
    // 或调用外部 AI 推理 API

    const input = await this.fetchTaskInput(task.workId);
    // const output = await aiModel.invoke(input, { signal });
    const output = `mock-output-${task.workId}`;
    const outputHash = crypto.createHash("sha256")
      .update(output)
      .digest("hex");
    const proofHash = crypto.createHash("sha256")
      .update(outputHash + this.config.workerId)
      .digest("hex");

    return {
      taskId: task.workId,
      output,
      outputHash,
      proofHash,
      gasUsed: 100000,
      status: "success",
    };
  }

  // === 生成执行证明 ===

  private async generateExecutionProof(
    result: ExecutionResult
  ): Promise<string> {
    // TODO: 实现实际证明生成
    // 可支持: ZK/SNARK 证明, TEE 证明, 或简单的哈希承诺
    return crypto.createHash("sha256")
      .update(result.outputHash + result.taskId + Date.now())
      .digest("hex");
  }

  // === 提交收据 (通过 Agent API) ===

  private async submitReceipt(
    taskId: string,
    result: ExecutionResult,
    proofHash: string
  ): Promise<void> {
    const response = await fetch(
      `${this.config.rpcEndpoint}/agent/v1/work/tasks/${taskId}/receipt`,
      {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-Key": process.env.AGENT_API_KEY || "",
        },
        body: JSON.stringify({
          provider_owner: process.env.WALLET_ADDRESS,
          receipt_hash: result.outputHash,
          output_hash: result.outputHash,
          proof_hash: proofHash,
          proof_level: "tee",
          runtime_hash: crypto.createHash("sha256")
            .update(this.config.workerId)
            .digest("hex"),
          status: result.status,
        }),
      }
    );

    if (!response.ok) {
      throw new Error(`Submit receipt failed: ${response.statusText}`);
    }
  }

  // === 获取任务输入 ===

  private async fetchTaskInput(taskId: string): Promise<string> {
    // TODO: 从 IPFS / L1 存储获取 Task 输入
    return `mock-input-${taskId}`;
  }

  // === Webhook 回调通知 ===

  private async notifyWebhook(
    taskId: string,
    result: ExecutionResult
  ): Promise<void> {
    if (!this.config.webhookUrl) return;

    await fetch(this.config.webhookUrl, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        event: "task.completed",
        taskId,
        outputHash: result.outputHash,
        status: result.status,
        timestamp: new Date().toISOString(),
      }),
    });
  }
}

// === 启动入口 ===

async function main() {
  const executor = new AIExecutor({
    chainId: "msg-chain-1",
    rpcEndpoint: process.env.RPC_ENDPOINT || "http://localhost:26657",
    mnemonic: process.env.WORKER_MNEMONIC || "",
    contractAddress: process.env.CONTRACT_ADDRESS || "",
    gasPrice: "0.025uom",
    workerId: process.env.WORKER_ID || "worker-1",
    maxConcurrent: parseInt(process.env.MAX_CONCURRENT || "5"),
    pollInterval: parseInt(process.env.POLL_INTERVAL || "5000"),
    webhookUrl: process.env.WEBHOOK_URL,
  });

  await executor.initialize();
  await executor.start();

  // Graceful shutdown
  process.on("SIGINT", async () => {
    await executor.stop();
    process.exit(0);
  });
}

if (require.main === module) {
  main().catch(console.error);
}

5.3 基于现有 Agent API 的集成

Executor 完全复用 MSG Chain 现有 Agent API 端点:

// === X-L2-Planning=true ===
// 文件: executor/src/agent-client.ts

/// Agent API 客户端 (复用未独立核验上线状态接口)
class AgentAPIClient {
  private baseUrl: string;
  private apiKey: string;

  constructor(baseUrl: string, apiKey: string) {
    this.baseUrl = baseUrl;
    this.apiKey = apiKey;
  }

  private async request(method: string, path: string, body?: any) {
    const response = await fetch(`${this.baseUrl}${path}`, {
      method,
      headers: {
        "Content-Type": "application/json",
        "X-API-Key": this.apiKey,
      },
      body: body ? JSON.stringify(body) : undefined,
    });
    return response.json();
  }

  // 未独立核验上线状态端点: 查询账户
  async getAccount(address: string) {
    return this.request("GET", `/agent/v1/query/account/${address}`);
  }

  // 未独立核验上线状态端点: 查询余额
  async getBalance(address: string) {
    return this.request("GET", `/agent/v1/query/balance/${address}`);
  }

  // 未独立核验上线状态端点: 查询交易
  async getTx(txHash: string) {
    return this.request("GET", `/agent/v1/query/tx/${txHash}`);
  }

  // 未独立核验上线状态端点: 查询区块
  async getBlock(height: number) {
    return this.request("GET", `/agent/v1/query/block/${height}`);
  }

  // 未独立核验上线状态端点: 事件历史
  async getEvents(type: string, address?: string) {
    const params = new URLSearchParams({ type });
    if (address) params.append("address", address);
    return this.request("GET", `/agent/v1/events/history?${params}`);
  }

  // 未独立核验上线状态端点: Oracle 价格
  async getOraclePrice(token: string) {
    return this.request("GET", `/agent/v1/oracle/price?token=${token}`);
  }

  // 未独立核验上线状态端点: Work 任务报价
  async offerWork(payload: any) {
    return this.request("POST", "/agent/v1/work/tasks/offer", payload);
  }

  // 未独立核验上线状态端点: 接受 Work 任务
  async acceptWork(workId: string, payload: any) {
    return this.request(
      "POST",
      `/agent/v1/work/tasks/${workId}/accept`,
      payload
    );
  }

  // 未独立核验上线状态端点: 提交 Work 收据
  async submitWorkReceipt(workId: string, payload: any) {
    return this.request(
      "POST",
      `/agent/v1/work/tasks/${workId}/receipt`,
      payload
    );
  }

  // 未独立核验上线状态端点: 结算 Work
  async settleWork(workId: string, payload: any) {
    return this.request(
      "POST",
      `/agent/v1/work/tasks/${workId}/settle`,
      payload
    );
  }

  // 未独立核验上线状态端点: 挑战 Work
  async challengeWork(workId: string, payload: any) {
    return this.request(
      "POST",
      `/agent/v1/work/tasks/${workId}/challenge`,
      payload
    );
  }

  // 未独立核验上线状态端点: 查询 Work 状态
  async getWork(workId: string) {
    return this.request("GET", `/agent/v1/work/tasks/${workId}`);
  }

  // 未独立核验上线状态端点: 查询 Work 追踪链
  async getWorkTrace(callChainId: string) {
    return this.request("GET", `/agent/v1/work/traces/${callChainId}`);
  }

  // 未独立核验上线状态端点: 注册 AI 模型
  async registerModel(payload: any) {
    return this.request("POST", "/agent/v1/models", payload);
  }

  // 未独立核验上线状态端点: 创建沙箱钱包
  async createSandboxWallet(payload: any) {
    return this.request("POST", "/agent/v1/sandbox/wallets/create", payload);
  }

  // 未独立核验上线状态端点: Payment 意图
  async paymentIntent(payload: any) {
    return this.request("POST", "/agent/v1/payments/intents", payload);
  }

  // 未独立核验上线状态端点: Payment 结算
  async paymentSettle(paymentId: string, payload: any) {
    return this.request(
      "POST",
      `/agent/v1/payments/${paymentId}/settle`,
      payload
    );
  }

  // 未独立核验上线状态端点: 查询 Worker 信誉
  async getReputation(providerAgent: string) {
    return this.request("GET", `/agent/v1/reputation/${providerAgent}`);
  }
}

5.4 Task Scheduler

// === X-L2-Planning=true ===
// 文件: executor/src/scheduler.ts

interface SchedulerConfig {
  maxRetries: number;
  retryDelay: number;
  workerBlacklistDuration: number;
}

class TaskScheduler {
  private workers: Map<string, WorkerInfo> = new Map();
  private queue: TaskOffer[] = [];
  private blacklist: Map<string, number> = new Map();
  private config: SchedulerConfig;

  constructor(config: SchedulerConfig) {
    this.config = config;
  }

  // 注册 Worker
  registerWorker(workerId: string, capabilities: string[], score: number) {
    this.workers.set(workerId, {
      workerId,
      capabilities,
      score,
      activeTasks: 0,
      lastHeartbeat: Date.now(),
    });
  }

  // 任务调度算法
  scheduleTask(task: TaskOffer): string | null {
    // 过滤: 有能力的、不在黑名单的、活跃任务最少的 Worker
    const candidates = Array.from(this.workers.values())
      .filter((w) => !this.blacklist.has(w.workerId))
      .filter((w) => w.capabilities.includes(task.capabilityRef))
      .sort((a, b) => a.activeTasks - b.activeTasks);

    if (candidates.length === 0) return null;

    // 选择负载最低的 Worker
    const selected = candidates[0];
    selected.activeTasks++;
    return selected.workerId;
  }

  // Task 失败处理
  handleTaskFailure(taskId: string, workerId: string) {
    const worker = this.workers.get(workerId);
    if (worker) {
      worker.activeTasks = Math.max(0, worker.activeTasks - 1);
      worker.score = Math.max(0, worker.score - 10);
    }

    // 加入黑名单
    this.blacklist.set(
      workerId,
      Date.now() + this.config.workerBlacklistDuration
    );

    // 重新入队
    const failedTask = this.queue.find((t) => t.workId === taskId);
    if (failedTask && failedTask.retries < this.config.maxRetries) {
      failedTask.retries++;
      setTimeout(() => {
        this.queue.push(failedTask);
      }, this.config.retryDelay);
    }
  }
}

6. 证明与验证

6.1 证明系统概览

证明系统确保 L2 执行结果可在 L1 上验证。支持以下证明类型:

证明级别 安全性 成本 适用场景
none 低 (信任假设) 无 测试、低价值任务
hash 中 (output commitment) 低 常规 AI 推理
tee 高 (硬件信任根) 中 隐私计算、高价值任务
zk 最高 (密码学证明) 高 金融计算、跨链验证
quorum 高 (多 Worker 共识) 中 关键决策、高频任务

6.2 Output Commitment 方案

Task 执行结果的承诺链:

input_data ──SHA3-256──► input_commitment
                                │
                      model_hash + runtime_hash
                                │
                    ┌───────────┴────────────┐
                    │   AI 推理执行            │
                    └───────────┬────────────┘
                                │
output_data ──SHA3-256──► output_commitment
                                │
              + execution_context (worker_id, timestamp, nonce)
                                │
              ──SHA3-256──► receipt_hash
                                │
              + proof_data (TEE quote / ZK proof / quorum sig)
                                │
              ──SHA3-256──► proof_commitment
// === X-L2-Planning=true ===
// 承诺生成逻辑

import { createHash, randomBytes } from "crypto";

interface CommitmentChain {
  inputCommitment: string;
  outputCommitment: string;
  receiptHash: string;
  proofCommitment: string;
}

function generateCommitmentChain(
  input: Buffer,
  output: Buffer,
  modelHash: string,
  runtimeHash: string,
  workerId: string,
  nonce: string = randomBytes(16).toString("hex")
): CommitmentChain {
  const inputCommitment = createHash("sha256").update(input).digest("hex");
  const outputCommitment = createHash("sha256").update(output).digest("hex");

  const receiptPayload = [
    outputCommitment,
    modelHash,
    runtimeHash,
    workerId,
    nonce,
  ].join("|");
  const receiptHash = createHash("sha256")
    .update(receiptPayload)
    .digest("hex");

  const proofPayload = [
    receiptHash,
    workerId,
    nonce,
  ].join("|");
  const proofCommitment = createHash("sha256")
    .update(proofPayload)
    .digest("hex");

  return { inputCommitment, outputCommitment, receiptHash, proofCommitment };
}

6.3 执行证明类型 (TypeScript)

// === X-L2-Planning=true ===
// 执行证明类型定义

/// TEE 证明 (基于 Intel SGX / AMD SEV)
interface TEEProof {
  proofType: "tee";
  teePlatform: "intel-sgx" | "amd-sev" | "arm-cca";
  quote: string;            // TEE 远程证明 Quote
  enclaveHash: string;      // Enclave 测量值 (MRENCLAVE)
  signerHash: string;       // 签名者哈希 (MRSIGNER)
  reportData: string;       // 报告数据 (包含 output_commitment)
  timestamp: number;
}

/// ZK 证明 (基于 zkSNARK / zkSTARK)
interface ZKProof {
  proofType: "zk";
  zkScheme: "groth16" | "plonk" | "stark";
  circuitHash: string;      // 电路哈希
  proof: string;            // ZK 证明数据 (bytes)
  publicInputs: string[];   // 公开输入
  verificationKey: string;  // 验证密钥哈希
}

/// 多 Worker 共识证明
interface QuorumProof {
  proofType: "quorum";
  quorumCount: number;      // 参与 Worker 数量
  threshold: number;        // 共识阈值
  signatures: WorkerSignature[];
  consensusHash: string;    // 共识结果哈希
}

interface WorkerSignature {
  workerId: string;
  signature: string;        // 对 output_commitment 的签名
  timestamp: number;
}

/// 统一证明类型
type ExecutionProof = TEEProof | ZKProof | QuorumProof;

/// 证明验证结果
interface VerificationResult {
  valid: boolean;
  verifiedAt: number;
  verifier: string;
  reason?: string;
}

6.4 验证策略

// === X-L2-Planning=true ===
// 验证器实现

class ProofVerifier {
  /// 验证执行证明
  async verifyProof(
    task: Task,
    receipt: Receipt,
    proof: ExecutionProof
  ): Promise<VerificationResult> {
    switch (proof.proofType) {
      case "tee":
        return this.verifyTEEProof(task, receipt, proof);
      case "zk":
        return this.verifyZKProof(task, receipt, proof);
      case "quorum":
        return this.verifyQuorumProof(task, receipt, proof);
      default:
        return {
          valid: false,
          verifiedAt: Date.now(),
          verifier: "ai-task-l2",
          reason: "unsupported_proof_type",
        };
    }
  }

  /// 验证 TEE 证明
  private async verifyTEEProof(
    task: Task,
    receipt: Receipt,
    proof: TEEProof
  ): Promise<VerificationResult> {
    // 1. 验证 TEE Quote 签名链 (验证 Intel/AMD 证书链)
    // 2. 验证 MRENCLAVE 匹配已知的受信任执行环境
    // 3. 验证 report_data 包含正确的 output_commitment
    // 4. 验证时间戳在有效窗口内

    const reportData = proof.reportData;
    const expectedData = receipt.outputCommitment + task.id;

    if (reportData !== expectedData) {
      return {
        valid: false,
        verifiedAt: Date.now(),
        verifier: "ai-task-l2",
        reason: "report_data_mismatch",
      };
    }

    // TEE quote 验证逻辑 (占位)
    const quoteValid = await this.verifyTEEQuote(proof.quote);
    if (!quoteValid) {
      return {
        valid: false,
        verifiedAt: Date.now(),
        verifier: "ai-task-l2",
        reason: "invalid_tee_quote",
      };
    }

    return { valid: true, verifiedAt: Date.now(), verifier: "ai-task-l2" };
  }

  /// 验证 ZK 证明
  private async verifyZKProof(
    task: Task,
    receipt: Receipt,
    proof: ZKProof
  ): Promise<VerificationResult> {
    // ZK 证明验证 (使用验证密钥和公开输入)
    // publicInputs = [input_commitment, output_commitment, model_hash, runtime_hash]

    const isValid = await this.verifyZKCircuit(
      proof.circuitHash,
      proof.proof,
      proof.publicInputs,
      proof.verificationKey
    );

    return {
      valid: isValid,
      verifiedAt: Date.now(),
      verifier: "ai-task-l2",
      reason: isValid ? undefined : "zk_proof_invalid",
    };
  }

  /// 验证共识证明
  private async verifyQuorumProof(
    task: Task,
    receipt: Receipt,
    proof: QuorumProof
  ): Promise<VerificationResult> {
    // 1. 验证签名 Worker 是否在注册表中
    // 2. 验证签名数量 >= 阈值
    // 3. 验证每个签名是否对应 output_commitment
    // 4. 验证签名是否有效 (Worker 公钥)

    if (proof.signatures.length < proof.threshold) {
      return {
        valid: false,
        verifiedAt: Date.now(),
        verifier: "ai-task-l2",
        reason: "insufficient_signatures",
      };
    }

    const validSigs = proof.signatures.filter((sig) =>
      this.verifyWorkerSignature(
        sig.workerId,
        receipt.outputCommitment,
        sig.signature
      )
    );

    return {
      valid: validSigs.length >= proof.threshold,
      verifiedAt: Date.now(),
      verifier: "ai-task-l2",
      reason:
        validSigs.length >= proof.threshold
          ? undefined
          : "signature_verification_failed",
    };
  }

  /// 验证 TEE Quote (占位)
  private async verifyTEEQuote(quote: string): Promise<boolean> {
    // TODO: 实现 Intel SGX / AMD SEV Quote 验证
    return true;
  }

  /// 验证 ZK 电路 (占位)
  private async verifyZKCircuit(
    circuitHash: string,
    proof: string,
    publicInputs: string[],
    verificationKey: string
  ): Promise<boolean> {
    // TODO: 实现 ZK 证明验证
    return true;
  }

  /// 验证 Worker 签名
  private verifyWorkerSignature(
    workerId: string,
    message: string,
    signature: string
  ): boolean {
    // TODO: 使用 Worker 公钥验证签名
    return true;
  }
}

6.5 挑战与争议流程

挑战流程:

                    ┌────────────┐
                    │  Task完成   │
                    └──────┬─────┘
                           │ 挑战窗口开启 (如 24h)
                           ▼
                    ┌────────────┐
                    │ 监控挑战事件 │◄── 任何人都可发起挑战
                    └──────┬─────┘
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
      ┌────────────────┐      ┌──────────────────┐
      │  无人挑战        │      │  有人发起挑战       │
      │  wait window    │      │  deposit + reason  │
      └────────┬───────┘      └────────┬─────────┘
               │                       │
               ▼                       ▼
      ┌────────────────┐      ┌──────────────────┐
      │  Auto Settle   │      │  Worker 回应机会   │
      │  释放奖励       │      │  (24h 回应窗口)    │
      └────────────────┘      └────────┬─────────┘
                                       │
                          ┌────────────┴────────────┐
                          │                         │
                          ▼                         ▼
                  ┌────────────────┐      ┌──────────────────┐
                  │  Worker 回应    │      │  Worker 未回应    │
                  │  提交反证       │      │  默认 Worker 有错  │
                  └────────┬───────┘      └────────┬─────────┘
                           │                       │
                           ▼                       ▼
                  ┌────────────────┐      ┌──────────────────┐
                  │  仲裁 / DAO    │      │  Slash Worker     │
                  │  判决           │      │  奖励挑战者        │
                  └────────┬───────┘      └──────────────────┘
                           │
              ┌────────────┴────────────┐
              │                         │
              ▼                         ▼
      ┌────────────────┐      ┌──────────────────┐
      │  Worker 胜诉    │      │  挑战者胜诉        │
      │  释放 Worker     │      │  Slash Worker     │
      │  惩罚挑战者       │      │  奖励挑战者        │
      └────────────────┘      └──────────────────┘
// === X-L2-Planning=true ===
// 挑战监控器

class ChallengeMonitor {
  private client: CosmWasmClient;
  private contractAddress: string;
  private challengeWindow: number; // seconds

  constructor(client: CosmWasmClient, contractAddress: string, challengeWindow: number) {
    this.client = client;
    this.contractAddress = contractAddress;
    this.challengeWindow = challengeWindow;
  }

  /// 监听挑战事件
  async watchChallenges(): Promise<void> {
    const events = await this.client.getEvents(
      this.contractAddress,
      { wasm: { action: "challenge_task" } },
      0, // from block
      Date.now() // to timestamp
    );

    for (const event of events) {
      const taskId = event.attributes.find((a) => a.key === "task_id")?.value;
      const challengeId = event.attributes.find(
        (a) => a.key === "challenge_id"
      )?.value;

      if (taskId && challengeId) {
        await this.handleChallenge(taskId, challengeId);
      }
    }
  }

  /// 处理挑战
  private async handleChallenge(
    taskId: string,
    challengeId: string
  ): Promise<void> {
    console.log(`[Challenge] Task ${taskId} challenged: ${challengeId}`);

    // 启动挑战倒计时
    setTimeout(async () => {
      const deadline = await this.getResponseDeadline(taskId);
      if (Date.now() > deadline) {
        await this.resolveChallenge(taskId, challengeId);
      }
    }, this.challengeWindow * 1000);
  }

  /// 获取回应截止时间
  private async getResponseDeadline(taskId: string): Promise<number> {
    const task = await this.client.queryContractSmart(
      this.contractAddress,
      { get_task: { task_id: taskId } }
    );
    return task.challenge_response_deadline;
  }

  /// 裁决挑战
  private async resolveChallenge(
    taskId: string,
    challengeId: string
  ): Promise<void> {
    // 如果 Worker 未在窗口内回应,自动裁决
    // 发送 resolve 交易到 L1
    console.log(`[Challenge] Resolving ${challengeId} for task ${taskId}`);
  }
}

7. 经济模型

7.1 Task 定价模型

Task 总成本 = L1 Gas 费 + L2 计算费

L1 Gas 费 = SubmitTxGas + ReceiptTxGas + SettleTxGas
           ≈ 300,000 gas × 0.025 uom/gas = 7,500 uom

L2 计算费 = model_compute_cost × input_size_multiplier
           + storage_cost × output_size
           + proof_generation_cost
定价参数 说明 默认值
base_compute_price 基础计算单价 100 uom/s
input_multiplier 输入大小倍率 size_bytes / 1024
output_multiplier 输出大小倍率 size_bytes / 1024
proof_markup 证明生成加成 ZK: 500%, TEE: 100%, hash: 0%
protocol_fee 协议手续费率 5%

7.2 Worker Bonding / Slashing

// === X-L2-Planning=true ===
// 质押与惩罚逻辑

/// Bond 池管理
pub struct BondPool {
    pub worker: Addr,
    pub total_bond: Uint128,
    pub locked_bond: Uint128,     // 当前任务中锁定的质押
    pub available_bond: Uint128,  // 可用质押
    pub reputation_score: u64,
    pub completed_tasks: u64,
    pub failed_tasks: u64,
    pub last_slash_time: u64,
}

/// Slashing 规则
pub enum SlashReason {
    InvalidOutput,         // 输出承诺与执行结果不匹配
    Timeout,              // 执行超时
    DoubleSubmission,     // 重复提交收据
    MaliciousBehavior,    // 恶意行为
    ChallengeLost,        // 挑战失败
}

/// Slashing 比例
pub fn get_slash_percentage(reason: SlashReason) -> u64 {
    match reason {
        SlashReason::InvalidOutput => 100,     // 100% of task bond
        SlashReason::Timeout => 25,             // 25%
        SlashReason::DoubleSubmission => 50,    // 50%
        SlashReason::MaliciousBehavior => 100,  // 100% + reputation reset
        SlashReason::ChallengeLost => 50,       // 50%
    }
}

7.3 奖励分配

Task 完成后的资金流:

Task Creator Deposit (1,000,000 uom)
│
├── 90% → Worker Payment (900,000 uom)
│   ├── 85% → Worker (base reward)
│   └── 5%  → Worker Pool (delegation rewards)
│
├── 5%  → Protocol Fee (50,000 uom) → Foundation Treasury
│
└── 5%  → Challenge Pool (50,000 uom)
    ├── Used for challenge deposits
    └── Distributed to successful challengers

7.4 争议费用

// === X-L2-Planning=true ===
// 争议经济模型

pub struct DisputeEconomics {
    /// 挑战押金比例 (相对于 task reward)
    pub challenge_deposit_percent: u64,  // 10%
    
    /// Worker 回应押金比例
    pub response_deposit_percent: u64,   // 5%
    
    /// 仲裁费用 (固定值 uom)
    pub arbitration_fee: Uint128,
    
    /// 挑战者奖励比例 (从 slashed bond)
    pub challenger_reward_percent: u64,  // 70%
    
    /// DAO 罚没收入比例
    pub dao_slash_percent: u64,          // 30%
}

/// 争议结果资金分配
pub fn distribute_dispute_funds(
    task_reward: Uint128,
    worker_bond: Uint128,
    challenge_deposit: Uint128,
    verdict: Verdict,
) -> Distribution {
    match verdict {
        Verdict::WorkerValid => {
            // Worker 获得奖励 + 返还挑战押金
            // 挑战者损失押金 -> 部分补偿 Worker
            Distribution {
                worker: task_reward + challenge_deposit * 70 / 100,
                challenger: challenge_deposit * 30 / 100,
                treasury: Uint128::zero(),
                dao: Uint128::zero(),
            }
        }
        Verdict::ChallengerValid => {
            // Worker 被 Slash
            // 挑战者获得奖励
            Distribution {
                worker: Uint128::zero(),
                challenger: worker_bond * 70 / 100 + challenge_deposit,
                treasury: Uint128::zero(),
                dao: worker_bond * 30 / 100,
            }
        }
        Verdict::Split => {
            // 按比例分配
            Distribution {
                worker: task_reward * 50 / 100,
                challenger: challenge_deposit,
                treasury: task_reward * 5 / 100,
                dao: worker_bond * 30 / 100,
            }
        }
    }
}

8. 前端

8.1 React Dashboard

// === X-L2-Planning=true ===
// 文件: frontend/src/App.tsx

import React, { useState, useEffect, useCallback } from "react";
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
import { TaskSubmissionForm } from "./components/TaskSubmissionForm";
import { TaskStatusTracker } from "./components/TaskStatusTracker";
import { WorkerStats } from "./components/WorkerStats";
import { DisputeManager } from "./components/DisputeManager";

// === 主应用 ===

function App() {
  return (
    <BrowserRouter>
      <div className="app-container">
        <nav className="sidebar">
          <h1>AI Task L2</h1>
          <ul>
            <li><Link to="/">Dashboard</Link></li>
            <li><Link to="/submit">Submit Task</Link></li>
            <li><Link to="/tasks">Task Status</Link></li>
            <li><Link to="/workers">Workers</Link></li>
            <li><Link to="/disputes">Disputes</Link></li>
          </ul>
        </nav>

        <main className="content">
          <Routes>
            <Route path="/" element={<Dashboard />} />
            <Route path="/submit" element={<TaskSubmissionForm />} />
            <Route path="/tasks" element={<TaskStatusTracker />} />
            <Route path="/workers" element={<WorkerStats />} />
            <Route path="/disputes" element={<DisputeManager />} />
          </Routes>
        </main>
      </div>
    </BrowserRouter>
  );
}

// === Dashboard ===

function Dashboard() {
  const [stats, setStats] = useState({
    totalTasks: 0,
    pendingTasks: 0,
    activeWorkers: 0,
    totalRewards: "0",
  });

  useEffect(() => {
    // 从 Agent API 获取统计信息
    fetchStats();
    const interval = setInterval(fetchStats, 10000);
    return () => clearInterval(interval);
  }, []);

  const fetchStats = async () => {
    try {
      const response = await fetch("/agent/v1/work/tasks?limit=1");
      const data = await response.json();
      setStats((prev) => ({
        ...prev,
        totalTasks: data.total || 0,
      }));
    } catch (err) {
      console.error("Failed to fetch stats:", err);
    }
  };

  return (
    <div className="dashboard">
      <h2>AI Task L2 Dashboard</h2>
      <div className="stats-grid">
        <div className="stat-card">
          <h3>Total Tasks</h3>
          <p>{stats.totalTasks}</p>
        </div>
        <div className="stat-card">
          <h3>Pending</h3>
          <p>{stats.pendingTasks}</p>
        </div>
        <div className="stat-card">
          <h3>Active Workers</h3>
          <p>{stats.activeWorkers}</p>
        </div>
        <div className="stat-card">
          <h3>Total Rewards</h3>
          <p>{stats.totalRewards} uom</p>
        </div>
      </div>
    </div>
  );
}

8.2 Task 提交表单

// === X-L2-Planning=true ===
// 文件: frontend/src/components/TaskSubmissionForm.tsx

import React, { useState } from "react";
import { useNavigate } from "react-router-dom";

interface TaskFormData {
  modelRef: string;
  modelHash: string;
  inputData: string;
  reward: string;
  challengeWindow: number;
  proofLevel: "none" | "hash" | "tee" | "zk";
  teeRequired: boolean;
  maxTimeout: number;
}

export function TaskSubmissionForm() {
  const navigate = useNavigate();
  const [formData, setFormData] = useState<TaskFormData>({
    modelRef: "",
    modelHash: "",
    inputData: "",
    reward: "1000000",
    challengeWindow: 86400,
    proofLevel: "hash",
    teeRequired: false,
    maxTimeout: 300,
  });
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setSubmitting(true);
    setError(null);

    try {
      // 计算 input commitment
      const inputCommitment = await sha256(formData.inputData);

      const payload = {
        model_ref: formData.modelRef,
        model_hash: formData.modelHash || inputCommitment,
        input_commitment: inputCommitment,
        reward: formData.reward,
        challenge_window: formData.challengeWindow,
        params: {
          proof_required: formData.proofLevel !== "none",
          tee_required: formData.teeRequired,
          max_timeout: formData.maxTimeout,
          input_format: "text",
          output_format: "json",
          min_worker_reputation: 0,
          quorum_count: 1,
        },
      };

      // 通过 Agent API 提交
      const response = await fetch("/agent/v1/work/tasks/offer", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "X-API-Key": process.env.REACT_APP_API_KEY || "",
        },
        body: JSON.stringify(payload),
      });

      if (!response.ok) {
        throw new Error(`Submission failed: ${response.statusText}`);
      }

      const result = await response.json();
      navigate(`/tasks?taskId=${result.data.work_id}`);
    } catch (err: any) {
      setError(err.message);
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <div className="task-form-container">
      <h2>Submit AI Task</h2>
      <form onSubmit={handleSubmit} className="task-form">
        <div className="form-group">
          <label>Model Reference</label>
          <select
            value={formData.modelRef}
            onChange={(e) =>
              setFormData({ ...formData, modelRef: e.target.value })
            }
          >
            <option value="">Select AI Model...</option>
            <option value="gpt4-model-v1">GPT-4 Model v1</option>
            <option value="llama3-model-v1">LLaMA 3 Model v1</option>
            <option value="stable-diffusion-v1">Stable Diffusion v1</option>
            <option value="custom">Custom Model</option>
          </select>
        </div>

        <div className="form-group">
          <label>Model Hash (SHA3-256)</label>
          <input
            type="text"
            value={formData.modelHash}
            onChange={(e) =>
              setFormData({ ...formData, modelHash: e.target.value })
            }
            placeholder="Optional - auto-calculated if empty"
          />
        </div>

        <div className="form-group">
          <label>Input Data</label>
          <textarea
            value={formData.inputData}
            onChange={(e) =>
              setFormData({ ...formData, inputData: e.target.value })
            }
            rows={6}
            placeholder="Enter task input data..."
          />
        </div>

        <div className="form-row">
          <div className="form-group">
            <label>Reward (uom)</label>
            <input
              type="text"
              value={formData.reward}
              onChange={(e) =>
                setFormData({ ...formData, reward: e.target.value })
              }
            />
          </div>

          <div className="form-group">
            <label>Challenge Window (seconds)</label>
            <input
              type="number"
              value={formData.challengeWindow}
              onChange={(e) =>
                setFormData({
                  ...formData,
                  challengeWindow: parseInt(e.target.value),
                })
              }
            />
          </div>
        </div>

        <div className="form-row">
          <div className="form-group">
            <label>Proof Level</label>
            <select
              value={formData.proofLevel}
              onChange={(e) =>
                setFormData({
                  ...formData,
                  proofLevel: e.target.value as any,
                })
              }
            >
              <option value="none">None (No Proof)</option>
              <option value="hash">Hash Commitment</option>
              <option value="tee">TEE Attestation</option>
              <option value="zk">ZK/SNARK Proof</option>
            </select>
          </div>

          <div className="form-group">
            <label>Max Timeout (seconds)</label>
            <input
              type="number"
              value={formData.maxTimeout}
              onChange={(e) =>
                setFormData({
                  ...formData,
                  maxTimeout: parseInt(e.target.value),
                })
              }
            />
          </div>
        </div>

        <div className="form-group checkbox">
          <label>
            <input
              type="checkbox"
              checked={formData.teeRequired}
              onChange={(e) =>
                setFormData({ ...formData, teeRequired: e.target.checked })
              }
            />
            Require TEE Execution
          </label>
        </div>

        {error && <div className="error-message">{error}</div>}

        <button type="submit" disabled={submitting}>
          {submitting ? "Submitting..." : "Submit Task"}
        </button>
      </form>
    </div>
  );
}

async function sha256(input: string): Promise<string> {
  const encoder = new TextEncoder();
  const data = encoder.encode(input);
  const hashBuffer = await crypto.subtle.digest("SHA-256", data);
  return Array.from(new Uint8Array(hashBuffer))
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
}

8.3 Task 状态追踪

// === X-L2-Planning=true ===
// 文件: frontend/src/components/TaskStatusTracker.tsx

import React, { useState, useEffect, useCallback } from "react";
import { useSearchParams } from "react-router-dom";

interface TaskStatus {
  id: string;
  status: string;
  modelRef: string;
  worker?: string;
  reward: string;
  createdAt: string;
  updatedAt: string;
  receipt?: {
    outputHash: string;
    proofHash: string;
    submittedAt: string;
  };
  challenge?: {
    id: string;
    challenger: string;
    reason: string;
    status: string;
  };
}

const STATUS_COLORS: Record<string, string> = {
  pending: "#f59e0b",
  accepted: "#3b82f6",
  executing: "#8b5cf6",
  completed: "#10b981",
  challenged: "#ef4444",
  disputed: "#f97316",
  settled: "#22c55e",
  cancelled: "#6b7280",
  expired: "#9ca3af",
};

export function TaskStatusTracker() {
  const [searchParams] = useSearchParams();
  const [tasks, setTasks] = useState<TaskStatus[]>([]);
  const [loading, setLoading] = useState(true);

  const initialTaskId = searchParams.get("taskId");

  const fetchTasks = useCallback(async () => {
    try {
      const url = initialTaskId
        ? `/agent/v1/work/tasks/${initialTaskId}`
        : "/agent/v1/work/tasks";

      const response = await fetch(url, {
        headers: { "X-API-Key": process.env.REACT_APP_API_KEY || "" },
      });
      const data = await response.json();
      const taskList = initialTaskId ? [data.data.work] : data.data.tasks;
      setTasks(taskList || []);
    } catch (err) {
      console.error("Failed to fetch tasks:", err);
    } finally {
      setLoading(false);
    }
  }, [initialTaskId]);

  useEffect(() => {
    fetchTasks();
    const interval = setInterval(fetchTasks, 5000);
    return () => clearInterval(interval);
  }, [fetchTasks]);

  if (loading) return <div className="loading">Loading tasks...</div>;

  return (
    <div className="task-tracker">
      <h2>Task Status</h2>
      {tasks.length === 0 ? (
        <p className="empty-state">No tasks found.</p>
      ) : (
        <div className="task-list">
          {tasks.map((task) => (
            <div key={task.id} className="task-card">
              <div className="task-header">
                <span className="task-id">{task.id}</span>
                <span
                  className="task-status"
                  style={{
                    backgroundColor:
                      STATUS_COLORS[task.status] || "#6b7280",
                  }}
                >
                  {task.status}
                </span>
              </div>

              <div className="task-details">
                <div className="detail-row">
                  <span className="label">Model:</span>
                  <span>{task.modelRef}</span>
                </div>
                <div className="detail-row">
                  <span className="label">Worker:</span>
                  <span>{task.worker || "Not assigned"}</span>
                </div>
                <div className="detail-row">
                  <span className="label">Reward:</span>
                  <span>{task.reward} uom</span>
                </div>
                <div className="detail-row">
                  <span className="label">Created:</span>
                  <span>
                    {new Date(task.createdAt).toLocaleString()}
                  </span>
                </div>

                {task.receipt && (
                  <div className="receipt-info">
                    <h4>Receipt</h4>
                    <div className="detail-row">
                      <span className="label">Output Hash:</span>
                      <code>{task.receipt.outputHash.slice(0, 16)}...</code>
                    </div>
                    <div className="detail-row">
                      <span className="label">Proof Hash:</span>
                      <code>{task.receipt.proofHash.slice(0, 16)}...</code>
                    </div>
                  </div>
                )}

                {task.challenge && (
                  <div className="challenge-info">
                    <h4>Challenge</h4>
                    <div className="detail-row">
                      <span className="label">Challenger:</span>
                      <span>{task.challenge.challenger}</span>
                    </div>
                    <div className="detail-row">
                      <span className="label">Reason:</span>
                      <span>{task.challenge.reason}</span>
                    </div>
                  </div>
                )}
              </div>

              <div className="task-actions">
                {task.status === "completed" && (
                  <button className="btn-settle"
                    onClick={() => handleSettle(task.id)}>
                    Settle
                  </button>
                )}
                {task.status === "completed" && (
                  <button className="btn-challenge"
                    onClick={() => handleChallenge(task.id)}>
                    Challenge
                  </button>
                )}
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

async function handleSettle(taskId: string) {
  await fetch(`/agent/v1/work/tasks/${taskId}/settle`, {
    method: "POST",
    headers: { "X-API-Key": process.env.REACT_APP_API_KEY || "" },
    body: JSON.stringify({
      amount: "0",
      settlement_hash: crypto.randomUUID(),
      escrow_release_hash: crypto.randomUUID(),
    }),
  });
}

async function handleChallenge(taskId: string) {
  const reason = prompt("Enter challenge reason:");
  if (!reason) return;

  await fetch(`/agent/v1/work/tasks/${taskId}/challenge`, {
    method: "POST",
    headers: { "X-API-Key": process.env.REACT_APP_API_KEY || "" },
    body: JSON.stringify({
      challenge_id: crypto.randomUUID(),
      reason,
      proof_hash: crypto.randomUUID(),
    }),
  });
}

8.4 Dispute 管理 UI

// === X-L2-Planning=true ===
// 文件: frontend/src/components/DisputeManager.tsx

import React, { useState, useEffect } from "react";

interface DisputeRecord {
  id: string;
  taskId: string;
  challenger: string;
  reason: string;
  status: "open" | "responded" | "resolved" | "expired";
  createdAt: string;
  workerResponse?: string;
  verdict?: string;
}

export function DisputeManager() {
  const [disputes, setDisputes] = useState<DisputeRecord[]>([]);

  useEffect(() => {
    fetchDisputes();
    const interval = setInterval(fetchDisputes, 10000);
    return () => clearInterval(interval);
  }, []);

  const fetchDisputes = async () => {
    try {
      const response = await fetch("/agent/v1/work/disputes", {
        headers: { "X-API-Key": process.env.REACT_APP_API_KEY || "" },
      });
      const data = await response.json();
      setDisputes(data.data?.disputes || []);
    } catch (err) {
      console.error("Failed to fetch disputes:", err);
    }
  };

  return (
    <div className="dispute-manager">
      <h2>Dispute Management</h2>
      <div className="dispute-list">
        {disputes.map((dispute) => (
          <div key={dispute.id} className={`dispute-card status-${dispute.status}`}>
            <div className="dispute-header">
              <span className="dispute-id">{dispute.id}</span>
              <span className="dispute-status">{dispute.status}</span>
            </div>
            <div className="dispute-details">
              <p><strong>Task:</strong> {dispute.taskId}</p>
              <p><strong>Challenger:</strong> {dispute.challenger}</p>
              <p><strong>Reason:</strong> {dispute.reason}</p>
              <p><strong>Created:</strong> {new Date(dispute.createdAt).toLocaleString()}</p>
              {dispute.workerResponse && (
                <p><strong>Worker Response:</strong> {dispute.workerResponse}</p>
              )}
              {dispute.verdict && (
                <p className={`verdict verdict-${dispute.verdict.toLowerCase()}`}>
                  <strong>Verdict:</strong> {dispute.verdict}
                </p>
              )}
            </div>
            {dispute.status === "open" && (
              <div className="dispute-actions">
                <button className="btn-respond">Respond as Worker</button>
                <button className="btn-escalate">Escalate to DAO</button>
              </div>
            )}
          </div>
        ))}
      </div>
    </div>
  );
}

9. 路线图

9.1 实施阶段

Phase 1: Task 合约部署 + 本地测试 (1-2 个月)
├── 实现 TaskManager 合约
├── 实现 ReceiptRegistry 合约
├── 单元测试 & 集成测试
├── 本地 MSG Chain 测试网部署
└── 基础 Task 生命周期验证

Phase 2: Off-chain Executor (1-2 个月)
├── 实现 Worker 节点框架
├── 实现 Task Scheduler
├── Agent API 集成 (复用现有端点)
├── Webhook 通知系统
└── Worker 注册与心跳机制

Phase 3: 证明系统 (2-3 个月)
├── Output Commitment 方案实现
├── TEE 证明验证器 (SGX/SEV)
├── ZK 证明电路设计与验证
├── 多 Worker 共识证明
└── L1 验证合约

Phase 4: 争议解决 (1 个月)
├── DisputeResolver 合约
├── 挑战窗口机制
├── 自动裁决逻辑
├── DAO 仲裁集成
└── Slashing 实现

Phase 5: 生产 L2 (2-3 个月)
├── 经济模型调优
├── 性能优化 & 基准测试
├── 安全审计
├── 主网上线
├── L1 Anchor 锚定机制
└── 跨链桥接 (IBC + 跨链结算)

9.2 里程碑

里程碑 时间 交付物 验证标准
M1 Month 1 Task 合约 v1 可通过 CLI 提交并查询 Task
M2 Month 2 Executor v1 端到端 Task 提交→执行→结算
M3 Month 3 Proof 系统 v1 TEE/ZK 证明可验证
M4 Month 4 Dispute 系统 挑战→争议→裁决全流程
M5 Month 6 L2 生产上线 运行中 Worker ≥ 10, 日任务量 ≥ 1000

9.3 当前依赖

已完成依赖:
  ✅ MSG Chain L1 主链 (msg-chain-1)
  ✅ CosmWasm 1.5 虚拟机
  ✅ Agent API (agent/v1)
  ✅ Agent Payment (agent_payment_v1)
  ✅ DAO Governance (dao_governance_v1)
  ✅ Foundation Treasury (foundation_treasury_v2)
  ✅ AI Agent Constitution (ai_agent_constitution_v1)
  ✅ Wallet/Key Management
  ✅ Event System
  ✅ Transaction Receipt System

规划中依赖 (X-L2-Planning=true):
  ❌ TaskManager 合约
  ❌ ReceiptRegistry 合约
  ❌ DisputeResolver 合约
  ❌ Settlement 合约
  ❌ L1 Anchor 锚定合约
  ❌ Off-chain Executor
  ❌ Proof 验证库
  ❌ TEE Attestation 验证
  ❌ ZK 证明电路
  ❌ Worker Registry

9.4 技术债务与风险

风险 影响 缓解措施
ZK 证明生成耗时 结算延迟 先实现 hash/tee 证明,ZK 作为可选项
TEE 兼容性 Worker 硬件要求高 支持多种 TEE (SGX/SEV/CCA)
挑战窗口过长 资金锁定时间长 动态挑战窗口 (根据任务价值/风险)
Worker 去中心化不足 单点故障 渐进式开放 Worker 注册
L2-L1 数据可用性 数据不可用导致争议失败 数据托管到 IPFS/Arweave

9.5 配置参考

MSG Chain 配置参考:

Chain ID:                msg-chain-1
Bech32 Prefix:           msg
Block Time:              5s
CosmWasm Version:        1.5
IBC:                     规划中 (X-L2-Planning=true)
跨链桥接:                 规划中 (X-L2-Planning=true)

Agent API:
  Rate Limit:            100 req/s
  Burst Limit:           200 req
  公开端点:              /agent/v1/query/account, balance, tx, block
                         /agent/v1/events/history, subscribe
                         /agent/v1/oracle/price
  保护端点:              /agent/v1/wallet/, mpc/sign, payment/session

已部署合约:
  dao_governance_v1:     治理提案/投票/时间锁/执行
  foundation_treasury_v2: 基金会金库/多签支付
  agent_payment_v1:       AI Agent 里程碑支付
  ai_agent_constitution_v1: AI 行为合规检查

注意: 本指南中所有标记 X-L2-Planning=true 的功能均处于规划阶段,代码为示意性设计参考,尚未经过安全审计,不可直接用于生产环境。实际部署前请参考最新版本的合约代码和部署文档。

参考架构:

  • Arbitrum L2 结算模型 (Optimistic Rollup + 挑战窗口)
  • Akash Network 计算市场 (去中心化计算资源匹配)