mcpField
F
flare-fcc

flare-fcc

github.com/flare-foundation开发2262 次安装2 周前更新
代码仓库

关于 flare-fcc

这是面向开发者的文档指导技能,介绍如何构建在可信执行环境中运行并连接 Flare 合约的 Flare Confidential Compute 扩展。它讲解架构和开发流程,但不代为执行交易、部署、密钥管理或 TEE 运维。

主要功能

  1. 01介绍 FCC 与 TEE 架构
  2. 02指导扩展和 InstructionSender 开发
  3. 03说明指令路由与操作标识符
  4. 04讲解 TEE 密钥、签名和加密载荷
  5. 05详述注册合约与指令生命周期

适用场景

  1. 01规划由合约触发的机密计算
  2. 02构建扩展的操作处理器
  3. 03将 InstructionSender 接入扩展
  4. 04检查输入验证与机密信息处理边界

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/flare-foundation/flare-ai-skills --skill flare-fcc

安装后在 Claude Code 中输入/flare-fcc确认已加载。

附带文件reference.md

详细介绍

范围与限制

此技能仅提供文档和指导。它说明 Flare Confidential Compute (FCC) 扩展和 TEE 机器的工作方式,以及开发者如何构建、注册和部署它们。它不会代替用户执行任何操作。

此技能明确不会:

  • 执行、签署或广播任何区块链交易
  • 访问、存储或传输私钥、部署者密钥或 TEE 持有的机密
  • 部署合约、注册扩展/TEE,或直接调用任何链上方法
  • 配置、证明或操作 Confidential Space VM
  • 处理资金、代币或任何金融资产

信任与外部数据处理:

  • TEE 扩展的核心目的在于保密性和可验证执行;扩展的安全性取决于其经证明的代码哈希,而非此技能。所有密钥生成、签署和机密处理都必须在 TEE 内部,或在用户控制、由开发者管理的环境中进行。
  • 到达扩展的指令载荷(OriginalMessage)是外部提供的不可信输入。请严格按照文档中的类型解码,验证每个字段,绝不要将原始载荷传入提示词、大模型输入或 Agent 决策逻辑。
  • 在链上存储加密机密不适合生产环境——链上数据是公开的,而且加密会随时间推移而减弱。请使用链下渠道传递机密(参见 fce-sign 警告)。

所有交易签署、密钥管理、证明和链上执行都完全在此技能之外进行。

Flare Confidential Compute (FCC) — TEE 扩展

FCC 是什么

Flare Confidential Compute(FCC) 让开发者能够在 可信执行环境(TEE) 中运行自定义代码——这是一种由硬件隔离的安全区(Flare 使用 GCP 的 Confidential Space(基于 AMD SEV))——并将该代码连接到 Flare 智能合约。部署单元称为扩展:一个在 TEE 内运行的 HTTP 服务器,用于接收源自链上交易的指令、执行机密逻辑,并返回可验证的结果。

当应用需要机密状态、保管秘密,或其完整性可在链上验证的链下计算时,请使用 FCC——例如,代表用户签名的密钥管理器、密封竞价拍卖、私密订单撮合,或任何“由区块链触发,但计算必须保持私密并经过证明”的工作负载。

FCC 目前处于开发的最后阶段。目前已在 Coston2 和 Coston 上提供,即将支持其他 Flare 网络——请从构建你的第一个扩展指南(Hello World 脚手架演示)开始。有关其机制的详细说明,请参阅 FCC 白皮书。

参考代码库:

  • flare-foundation/fce-extension-scaffold — 一个可运行的“Hello World”扩展,包含合约、部署/注册工具,以及 Claude Code 技能(/create-extension、/rename-scaffold、/test-extension、/verify-deploy)。使用 Go、Python 和 TypeScript 实现——在 .env 中设置 LANGUAGE=go|python|typescript(默认使用 Go;不同语言的合约、脚本和 Coston2 流程保持一致)。这是构建自定义扩展的起点;入门指南将带你完整走一遍流程。
  • flare-foundation/fce-sign — 一个示例扩展,用于存储私钥并使用该密钥签名消息,提供 Go、Python 和 TypeScript 版本。演示 TEE 签名端口和可复现构建。链上秘密部分明确仅用于演示。
  • flare-foundation/fce-weather-insurance — 一个完整的 FCC 应用,演示参数化降雨保险。投保人在链上购买保障;TEE 获取 OpenWeatherMap 数据并签署结算结果;任何人都可以调用 settle() 进行验证并支付赔款。支持公开保单和 ECIES 加密的私密保单。包含 Next.js dApp 前端。

指令生命周期

扩展只控制两部分:链上合约(步骤 1)和动作处理器(步骤 6)。中间的所有环节均由 TEE 基础设施处理。

1. User calls your InstructionSender contract (on-chain)
2. Contract routes through TeeExtensionRegistry.sendInstructions() → emits TeeInstructionsSent
3. TEE proxy picks up the instruction from the chain
4. TEE node fetches the instruction from the proxy
5. TEE node forwards it as POST /action to your extension server (inside the TEE)
6. Your extension decodes, validates, executes, and returns a result
7. TEE node returns the (optionally cosigned) result to the proxy
8. Caller polls the proxy for the result

链上构建模块

系统由两个协议合约(来自 flare-smart-contracts-v2)作为入口:

  • TeeExtensionRegistry — 扩展注册表,也是提交指令的唯一途径。主要接口:
    • sendInstructions(address[] _teeIds, TeeInstructionParams _params) payable returns (bytes32 instructionId) — 唯一的入口点。TeeInstructionParams = { bytes32 opType; bytes32 opCommand; bytes message; address[] cosigners; uint64 cosignersThreshold; address claimBackAddress; }。
    • nextPublicExtensionId() 和 getTeeExtensionInstructionsSender(uint256 extensionId) — 用于查找扩展的 ID。公开扩展 ID 从 0x10000(65536)开始;低于该值的 ID 保留给系统扩展,因此 setExtensionId() 会从 0x10000 扫描到 nextPublicExtensionId(),而不是从零开始。
    • **访问控制:**注册扩展时,必须将其绑定到一个 InstructionSender 地址。注册表会拒绝任何 msg.sender 不是该地址的 sendInstructions 调用——无论是 EOA 还是其他合约都不行。
  • TeeMachineRegistry — 将扩展映射到为其提供服务的 TEE 机器。getRandomTeeIds(uint256 _extensionId, uint256 _count) 会选取机器地址,以便将指令路由给它们(使用 _count > 1 可将一条指令分发给多个 TEE)。

在链上,这两个合约都由**一个 EIP-2535 diamond(FlareTeeManager)**承载——调用 diamond 地址;IFlareTeeManager 是聚合接口。上文提到的 TeeExtensionRegistry 接口属于 diamond 的 IExtensionManager facet;TeeMachineRegistry 的接口属于 IMachineManager。另外还有两个日常使用的重要 facet:IVerification(attestation/可用性检查请求、共同签名者、ChallengeExpired/InvalidAttestation 错误)和 IOperationFees(按指令查询费用——getOperationFee、calculateFeeByTeeIds)。IOwnerAllowlist 用于限制可注册扩展、机器或钱包项目所有者的对象。ITeeCommonErrors 包含多个 facet 共用的错误,包括上文已提到的错误(TooMany、ChallengeExpired、InvalidGovernanceHash)。完整 ABI 参考:FCC Reference(IFlareTeeManager、IExtensionManager、IMachineManager、IVerification、IOperationFees、IOwnerAllowlist、ITeeCommonErrors)。FlareTeeManager 在主网上部署后,应在运行时通过 FlareContractRegistry 解析其地址,而不是将地址硬编码;目前已部署在 Coston2、Coston 和 Songbird 上。

InstructionSender 合约

这是你的合约,也是唯一允许为你的扩展提交指令的地址。最低要求:

  1. 知道其扩展 ID — 用于查找提供服务的 TEE 机器。脚手架中的 setExtensionId() 会在注册后扫描注册表(从第一个公共扩展 ID 0x10000 开始),并缓存该 ID(仅设置一次)。
  2. 在 TeeExtensionRegistry 上调用 sendInstructions,并提供至少一个 teeId、opType/opCommand bytes32 标识符、非空的 message,以及(通常为空的)协签者。
  3. 设为 payable 并转发 msg.value — 注册表会收取每条指令的费用。
  4. 在注册前部署 — 注册时需要传入已部署的 InstructionSender 地址。

脚手架中的 HelloWorldInstructionSender 是现成模板:它定义了 bytes32 操作常量,并为每个操作提供一个 payable 发送函数(sendSayHello、sendSayGoodbye)。你也可以编写自定义的最简发送合约,以实现自定义访问控制、链上验证、多 TEE 路由、协签者工作流或批处理 — 注册表只关心已注册的地址是否使用有效参数调用 sendInstructions。

OPType / OPCommand 路由模型

合约与扩展代码通过两级标识符关联,这些标识符在三个层之间必须完全一致:

层操作类型命令
Soliditybytes32 OP_TYPE_GREETING = bytes32("GREETING")bytes32 OP_COMMAND_SAY_HELLO = bytes32("SAY_HELLO")
Go 配置OPTypeGreeting = "GREETING"OPCommandSayHello = "SAY_HELLO"
Go 路由器dataFixed.OPType == teeutils.ToHash(config.OPTypeGreeting)df.OPCommand == teeutils.ToHash(config.OPCommandSayHello)

OPType 用于选择操作组;OPCommand 用于在组内进一步路由。OPType 不匹配时会进入“unsupported op type”分支;OPCommand 不匹配时会进入“unsupported op command”分支。bytes32("...") 最多只能容纳 31 个字节 — 标识符应保持简短。

保留名称: OPType 中的 F_ 前缀保留给 Flare 系统操作(F_REG、F_WALLET、F_GET、F_POLICY、F_GOVERNANCE、F_XRP、F_BTC、F_FDC2)— 切勿为自己的 OPType 添加 F_ 前缀。它们的命令名称也同样保留(TEE_ATTESTATION、TEE_INFO、TEE_BACKUP、KEY_GENERATE、KEY_INFO、KEY_PROOF、KEY_DELETE、KEY_DIRECT_BACKUP、KEY_DIRECT_RESTORE、KEY_DATA_PROVIDER_RESTORE、INITIALIZE_POLICY、UPDATE_POLICY、SET_MACHINE_PATH_LIST、PAY、REISSUE、VRF、PROVE)— 在自定义的非 F_ OPType 下复用这些命令名称,会通过本地验证,但指令永远不会到达你的扩展(也不会报错),因此两者都应使用特定于业务领域的名称。

TEE 密钥与签名模型

每台 TEE 机器启动时都会生成一对身份密钥(基于 secp256k1 的 ECDSA,与 Ethereum 风格的密钥相匹配)。私钥部分永远不会离开 enclave。

  • 公钥 — 可验证的身份;可以存储在链上,也可以通过代理的 /info 端点提供。任何人都可以验证 ECDSA 签名,并向该公钥加密 ECIES 载荷。
  • 私钥 — 仅限 enclave 使用。用于签名结果(ECDSA),以及解密发送给该机器的载荷(ECIES)。

ECDSA 用于证明来源(相当于在公开消息上盖章);ECIES 用于隐藏内容(相当于只有匹配的私钥才能打开的保险箱)。不要混淆两者——使用私钥加密是错误的做法。

机密数据的处理模式:**在链下加密至 TEE 的公钥,并且只在 enclave 内解密。**扩展程序本身不持有身份私钥——它会在本地调用 TEE 节点(签名端口上的 POST /decrypt,仅限 localhost),由节点使用 enclave 持有的密钥进行解密。加密可以隐藏字节,但不能代替下文的共识检查。

数据提供者和联签者决定 TEE 是否可以执行工作。只有在 Flare Systems Protocol 数据提供者中继指令,并使用超过当前签名策略权重 50% 的权重对其签名后,链上指令才会执行(该加权集合与 FTSO/FDC 使用的集合相同)——代理不能自行授权执行操作。对于敏感操作(付款、密钥管理),联签者会增加第二道独立的授权关卡:必须同时提供两类签署——提供者权重和联签者阈值,否则 TEE 不会执行。

有关完整机制,请参阅 TEE 公钥和私钥和数据提供者和联签者。

扩展程序(Go)——操作处理程序

在 TEE 内部,扩展程序是一个 HTTP 服务器。TEE 节点会通过 POST /action 发送每条指令。你需要实现 processAction,解析操作中的 instruction.DataFixed(包含 OPType、OPCommand 和原始 OriginalMessage),然后根据 OPType 进行分发,再根据 OPCommand 进行路由。

每个处理程序都遵循相同的4 步模式:

func (e *Extension) processSayHello(action teetypes.Action, df *instruction.DataFixed) teetypes.ActionResult {
    // 1. DECODE the raw OriginalMessage (JSON here; use structs.DecodeTo for ABI-encoded)
    var req types.SayHelloRequest
    dec := json.NewDecoder(bytes.NewReader(df.OriginalMessage))
    dec.DisallowUnknownFields()
    if err := dec.Decode(&req); err != nil {
        return buildResult(action, df, nil, 0, fmt.Errorf("decoding request: %w", err))
    }

    // 2. VALIDATE every field — this is untrusted external input
    if req.Name == "" {
        return buildResult(action, df, nil, 0, fmt.Errorf("name must not be empty"))
    }

    // 3. EXECUTE your confidential logic (guard shared state with the mutex)
    e.mu.Lock()
    e.greetingCount++
    n := e.greetingCount
    e.mu.Unlock()

    // 4. BUILD the result: status 1 = success (data returned), status 0 = error (err logged)
    data, _ := json.Marshal(types.SayHelloResponse{Greeting: "Hello, " + req.Name, GreetingNumber: n})
    return buildResult(action, df, data, 1, nil)
}

开发者需要修改的文件(脚手架会用 ★ 标记这些文件,/rename-scaffold 可自动重命名 Hello World 占位内容):

  1. go/internal/config/config.go — OPType/OPCommand 字符串常量和版本
  2. go/pkg/types/types.go — 请求/响应/状态结构体
  3. go/internal/extension/extension.go — 路由分支和处理程序(主要的自定义位置)
  4. contracts/InstructionSender.sol — 对应的 bytes32 常量和发送函数
  5. tools/cmd/run-test/main.go — 端到端测试载荷和断言

编辑合约后,运行 ./scripts/generate-bindings.sh 重新生成 Go 绑定。

TEE 签名端口

需要使用 TEE 管理的密钥进行签名、证明或加密的扩展程序,会在扩展程序内部调用 TEE 的签名端口(例如 localhost:7701/SIGN_PORT,或某些文档中的 9090——请查看脚手架的配置)。fce-sign 正是通过这种方式对消息进行签名,而密钥永远不会离开 enclave。

fce-sign:私钥扩展程序示例

fce-sign 仓库演示了完整的 TEE 工作流:存储 ECIES 加密的私钥,并对任意消息签名。提供 Go、Python 和 TypeScript 版本(在 .env 中设置 LANGUAGE)。

Docker 服务架构

三个容器以 Docker 服务的形式运行:

  • extension-tee — 你的扩展程序代码。接收代理解码后的指令并返回结果。
  • ext-proxy — 监控链上的新指令,将其转发给你的处理程序,并将结果提交回链上。
  • redis — 代理使用的内存存储。
端口参考(fce-sign)
服务容器端口主机端口
ext-proxy 内部66636673
ext-proxy 外部66646674
redis63796382

ngrok 将主机端口 6674(ext-proxy 外部)暴露到互联网。内部端口 6673 用于扩展容器与 Docker 内代理之间的通信。

在 Coston2 上部署 fce-sign(本地模拟 TEE)

前提条件:Docker Desktop、Foundry、Go、ngrok,以及已注资的 Coston2 钱包。

步骤 0 — 激活本地模拟模式:

./scripts/use-chain.sh local coston2 go   # or python / typescript

设置 SIMULATED_TEE=true 和 LOCAL_MODE=false(真实 Coston2 链,模拟证明)。运行 ./scripts/use-chain.sh --list 查看所有选项。

步骤 1 — 配置部署者密钥,编辑 .env.local.coston2:

DEPLOYMENT_PRIVATE_KEY="<funded-coston2-private-key-hex-no-0x>"
INITIAL_OWNER="0x<your-address>"

编辑后重新运行 use-chain.sh,使 .env 获取更改。

步骤 2 — 预留公共代理 URL(在另一个终端中):post-build.sh、start-services.sh 和 test.sh 都会从 .env 读取 EXT_PROXY_URL,因此请在部署合约或启动 Docker 服务之前设置该值。

安全提示:ngrok http 6674 会将本地 ext-proxy 暴露到公网 — 端口 6674 会开放代理 HTTP API,任何拥有该 URL 的人都能调用它。ngrok 仅用于 Coston2 测试网,完成后请停止隧道。

ngrok http 6674

复制 ngrok Forwarding 行中的 HTTPS URL,将其设置为 .env.local.coston2 中的 EXT_PROXY_URL,然后重新运行 use-chain.sh。此时代理尚未运行 — 第 5 步启动 ext-proxy 后,ngrok 才会转发流量。ngrok 免费版会在重启后保持该 URL 不变,因此通常只需设置一次。

步骤 3 — 部署合约并注册扩展:

./scripts/pre-build.sh

编译 Solidity、部署 InstructionSender,并在链上注册扩展。将 EXTENSION_ID 和 INSTRUCTION_SENDER 写入 config/extension.env。

警告:config/extension.env 一旦存在,pre-build 就会拒绝再次运行。只有在确实要创建新扩展时才使用 --force — 这会部署新的 InstructionSender 并注册新的扩展 ID;如果旧 TEE 机器仍以先前的扩展 ID 注册,就会导致 MachineManager.TooMany()。

步骤 4 — 配置索引器数据库:

cp config/proxy/extension_proxy.coston2.docker.toml.example \
   config/proxy/extension_proxy.coston2.docker.toml

编辑 [db] 配置块,填入 Coston2 索引器凭据(主机 34.38.42.208、端口 3306、数据库 indexer)。凭据可通过 支持渠道 或 @flare_network 申请获取。

步骤 5 — 启动扩展服务栈:

./scripts/start-services.sh

构建扩展镜像,然后启动 redis、ext-proxy 和 extension-tee。脚本本身会等待 EXT_PROXY_URL/info — 如果第 2 步启动的 ngrok 仍在运行,该检查会通过公共隧道访问本地代理。在本地等待代理就绪:until curl -sf http://localhost:6674/info >/dev/null 2>&1; do sleep 2; done。确认只有扩展代理在监听 6674:lsof -i :6674。

步骤 6 — 验证代理:

curl -s "$EXT_PROXY_URL/info" | jq '.machineData'

模拟 TEE:codeHash = 0x194844cf…,extensionId 与 config/extension.env 中的值一致,initialOwner 与你的地址一致。

步骤 7 — 注册 TEE 机器:

./scripts/post-build.sh

运行三个链上步骤:allow-tee-version(将代码哈希加入白名单)、set-governance(注册扩展的 TEE 治理签名者集合和阈值 — 除非你在 .env 中设置 GOVERNANCE_SIGNERS/GOVERNANCE_THRESHOLD,否则默认由部署者作为唯一签名者,阈值为 1),以及 register-tee -command rRap(注册机器、签发新的证明、运行 FTDC 检查,并将其提升至生产环境)。治理集合必须与 extension-tee 节点容器获得的配置一致,否则注册会因 InvalidGovernanceHash 而回滚。

步骤 8 — 运行端到端测试:

./scripts/test.sh

流程:setExtensionId() → 获取 TEE 公钥 → 使用 ECIES 加密测试私钥 → 在链上调用 updateKey → 等待处理完成 → 在链上调用 sign → 验证 ECDSA 签名是否匹配。

Python 和 TypeScript 处理器框架

Python 和 TypeScript 使用 Framework 类,按 (opType, opCommand) 对注册处理器:

def register(framework: Framework) -> None:
    framework.handle(OP_TYPE_KEY, OP_COMMAND_UPDATE, handle_key_update)
    framework.handle(OP_TYPE_KEY, OP_COMMAND_SIGN, handle_key_sign)

每个处理器都会接收十六进制编码的 originalMessage,并返回 (data, status, error):

  • **data:**以十六进制编码的返回数据,会写回链上;也可以是 None
  • status:0 = 错误,1 = 成功,>=2 = 待处理
  • **error:**处理器失败时的错误消息字符串

base/ 包(Python/TypeScript)提供 hex_to_bytes/bytes_to_hex 和 Framework HTTP 服务端。请勿修改 base/——它属于框架基础设施。

fce-sign 项目结构
sign/
├── contracts/                   # Solidity contracts (shared)
├── config/
│   ├── extension.env            # Generated by pre-build.sh
│   ├── coston2/deployed-addresses.json
│   └── proxy/                   # ext-proxy TOML configs
├── scripts/                     # use-chain.sh, pre-build.sh, start-services.sh, post-build.sh, test.sh
├── go/internal/extension/       # Go business logic (modify)
├── go/tools/cmd/                # Deploy CLIs (Go-only, shared across all languages)
├── python/app/                  # Python business logic (modify)
├── python/base/                 # Framework infrastructure (do not modify)
├── typescript/src/app/          # TypeScript business logic (modify)
├── typescript/src/base/         # Framework infrastructure (do not modify)
├── docker-compose.yaml
├── .env.example
└── .env.local.coston2
基于 fce-sign 构建自己的扩展
  1. 克隆仓库并选择一种语言。
  2. 在 Solidity 合约和处理器中定义 opType/opCommand 常量。
  3. 使用你的常量和参数修改 contracts/InstructionSender.sol。
  4. 在 go/internal/extension/(Go)或 app/(Python/TypeScript)中编写处理器。
  5. 按照上述部署步骤操作——无论使用哪种语言,go/tools/ 部署 CLI 都可共用。
清理

停止整个栈:

./scripts/stop-services.sh

完全重置(从头开始):

./scripts/stop-services.sh
docker compose down --rmi local
rm -f .env config/extension.env config/proxy/extension_proxy.coston2.docker.toml

然后从步骤 0 重新开始。注意:链上状态(已部署的合约、已注册的扩展、TEE)无法重置——每次运行 pre-build.sh 都会部署新合约。

fce-sign 故障排查
  • 代理无法启动 / 数据库同步错误——检查 docker compose logs ext-proxy;确认 config/proxy/extension_proxy.coston2.docker.toml 中的数据库凭据。
  • 交易回滚——C2FLR 不足;使用 Coston2 水龙头。
  • MachineManager.TooMany()——config/extension.env 中的扩展 ID 与链上 TEE 记录不匹配(通常发生在 pre-build.sh --force 之后)。请完全重置,或保留现有的 extension.env,并仅重新运行 post-build.sh + test.sh。
  • Verification.ChallengeExpired——重新运行 post-build.sh。
  • InvalidGovernanceHash——set-governance 使用的 GOVERNANCE_SIGNERS/GOVERNANCE_THRESHOLD 与 TEE 节点签名的治理哈希不匹配;默认仅由部署者管理时,请将两者都留空;或者确保 .env 与节点容器配置一致,然后重新运行 post-build.sh。
  • code hashes do not match——SIMULATED_TEE 与容器 MODE 不一致;请使用 SIMULATED_TEE=true 和 MODE=1(由 Docker Compose 注入)。
  • TEE 注册超时——尝试运行 docker compose restart ext-proxy;FDC 证明需要 Coston2 上有活跃的中继提供方。
  • ngrok URL 已更改——更新 .env.local.coston2 中的 EXT_PROXY_URL,重新运行 use-chain.sh;如有需要,重启 ngrok 隧道(ngrok http 6674),重启 Docker 栈,然后重新运行 post-build.sh 和 test.sh。

fce-weather-insurance:参数化保险示例

fce-weather-insurance 仓库是一个完整的 FCC 应用:在 enclave 中使用 OpenWeatherMap 数据结算参数化降雨保险。它展示了 TEE 工作负载的一种模式:获取链下数据、对结果签名,并由链上合约验证该签名后再转移资金——这与任何由预言机支持的结算流程类似。请参阅 flare-foundation/fce-weather-insurance-x402-agent,了解如何使用 x402 payments 通过 AI Agent 向此扩展购买并结算保单。

流程
  1. 保单持有人为某个日期和地点购买降雨保障,并支付 ERC-20 保费(payToken);合约从资金池流动性中预留赔付金额。
  2. 从 settlementUnlockAt 开始(保障日期次日 00:00 UTC),keeper 调用 requestSettlement,将 WEATHER/SETTLE 指令路由到扩展。
  3. 扩展在飞地内从 OpenWeatherMap 获取当天的降水量,并签署结算结果。
  4. 任何人都可以使用签名后的 ActionResult 调用 settle();合约会将结果哈希封装在一个域分隔载荷中,通过 ecrecover 恢复签名者,要求其与注册的 teeAddress 一致,并在达到降雨阈值时支付赔款。
OP 标识符(OP_TYPE_WEATHER = bytes32("WEATHER"))
命令用途
FETCH返回某个城市当前天气的 JSON(用于测试 / dApp 显示)。
SETTLE获取保单的每日降雨量,并返回签名后的结算载荷。
BUY解密经过 ECIES 加密的私人保单,并返回经证明的条款。

一如既往,WeatherInsurance.sol 和 internal/config/config.go 中的常量必须完全一致。

公开保单与私人保单
  • 公开购买(buyPolicy):所有条款都在链上;调用者需先对保费调用 approve。
  • 私人购买(buyPolicyPrivate):买方使用扩展的公钥对 ABI 编码的 PrivateBuyParams 进行 ECIES 加密;密文作为 WEATHER/BUY 指令发送。TEE 通过节点的 /decrypt 端点解密,并在飞地内以 termsCommitment 为键保存阈值;随后买方通过 relayPrivateBuy 完成购买(该函数会验证 TEE 签名)。结算前,链上只有承诺值。
TEE 签名验证

relayPrivateBuy 和 settle 都以相同方式验证 TEE 结果:重建节点签名的哈希并恢复签名者,要求其与 teeAddress 一致。

bytes32 resultHash = keccak256(abi.encodePacked(
    keccak256(_resultData), _actionId, keccak256(bytes(_submissionTag)), _status));
// Domain-separated payload — must match go-flare-common signing.TEEActionResult
bytes32 payloadHash = keccak256(abi.encode(bytes32("TEE_ACTION_RESULT"), block.chainid, resultHash));
address signer = _recover(_ethSigned(payloadHash), _signature); // EIP-191 personal-sign
require(signer == teeAddress, "bad TEE signature");

节点使用 EIP-191 前缀对 keccak256(abi.encode(TEE_ACTION_RESULT_PREFIX, chainId, ActionResult.Hash())) 签名,而不是仅对 ActionResult.Hash() 签名;只接受成功的结果(status == 1)。使用原始的 resultHash 进行验证,无法通过当前 TEE 节点签名的验证。SettlementTime(一个库)会计算 settlementUnlockAt,即保障日期次日的 UTC 午夜。

部署说明(与 scaffold/fce-sign 不同)
  • 使用 ./scripts/use-chain.sh local coston2 激活(无需语言参数——此应用使用 Go)。
  • 在 .env.local.coston2 中设置 OPENWEATHERMAP_API_KEY 和 PAY_TOKEN。Coston2 上有一个模拟 ERC-20,地址为 0x53192e788991AD96bC180249B15AefB94E597dD1;你也可以部署自己的代币。
  • 先运行 ./scripts/pre-build.sh,然后运行 ./scripts/extension-setup.sh 进行部署(后者会对已部署的合约调用 setPayToken)。其余步骤(在 6674 端口运行 ngrok、post-build.sh、证明、代码哈希列入白名单)与下方 scaffold 生命周期相同。

证明与可复现构建

TEE 的信任来自远程证明:Confidential Space VM 会测量正在运行的镜像并报告代码哈希。Flare 的数据提供方(FTDC)只接受来自代码哈希已针对该扩展加入链上白名单的 TEE 的结果。因此,构建具有关键的安全性影响:

  • MODE=0 是生产环境的证明后端;MODE=1 会生成 FTDC 不接受的模拟证明。对于测试网/主网,镜像必须内置 MODE=0,且 .env 必须设置 LOCAL_MODE=false / SIMULATED_TEE=false。
  • **可复现性:**设置 SOURCE_DATE_EPOCH(例如,最后一次提交的时间),以确保相同源码生成相同代码哈希。Go 路径可在不同机器间实现逐位可复现(单个静态二进制文件)。Python/TypeScript 可实现同一台机器上的确定性,但跨机器逐位可复现只能尽力而为(pip wheel / node_modules 会嵌入主机路径)——在另一台机器上重新构建可能会更改代码哈希,并要求重新注册。fce-sign 通过 .env 中的 LANGUAGE=go|python|typescript 选择语言。

部署生命周期(Coston / Coston2)

脚手架脚本会依次执行四个阶段(./scripts/full-setup.sh --chain coston2 --test 会一次性运行全部阶段;每个阶段也可以单独运行):

  1. 预构建(pre-build.sh)——编译并部署 InstructionSender,在 TeeExtensionRegistry 上注册扩展,并将 EXTENSION_ID + INSTRUCTION_SENDER 写入 config/extension.env。重新运行时会复用现有的 config/extension.env,而不是拒绝运行;只有在明确要创建新扩展时才传入 --force。
  2. 启动服务(docker compose up -d --build)——以容器形式运行 redis、ext-proxy 和 extension-tee(你的代码)。本地设置 LOCAL_MODE=true 会跳过证明。
  3. 构建后(post-build.sh)——allow-tee-version 将代码哈希加入白名单,set-governance 注册扩展的 TEE 治理签名者集合/阈值(除非设置了 GOVERNANCE_SIGNERS / GOVERNANCE_THRESHOLD,否则默认为部署者且阈值为 1),然后 register-tee 在链上注册 TEE 机器。使用 register-tee -command rRap,以便重新运行时发起新的证明质询(大写 R),避免出现 Verification.ChallengeExpired。
  4. 测试(test.sh)——通过已部署的 TEE 发送指令并验证往返结果。

真实测试网还需要:已注资的部署者密钥(Coston2 水龙头)、可公开访问的代理 URL(任何转发到端口 6674 的 HTTPS 隧道,例如 ngrok 或 cloudflared)、代理的索引器数据库凭据,以及用于运行镜像的 GCP Confidential Space VM。通过向代理 /info 发送 curl 请求并确认 machineData 来验证部署:platform 以 0x4743505f414d445f534556…(GCP_AMD_SEV)开头,codeHash 是真实测量的哈希(而非模拟值 0x194844cf…),且 extensionId / initialOwner 与 config/extension.env 中的值相符。如果重新部署了 FlareTeeManager diamond,所有注册都会被清除——重新运行预构建以获取新的 EXTENSION_ID,让 VM 操作员使用新 ID 重启,然后重新运行构建后和测试。

常见故障模式
  • Verification.TeeNotFound —— NORMAL_PROXY_URL 指向了错误链的 FTDC 代理。
  • Verification.ChallengeExpired —— 重新运行构建后;确保 register-tee 使用 -command rRap。
  • InvalidGovernanceHash —— GOVERNANCE_SIGNERS / GOVERNANCE_THRESHOLD 与 TEE 节点签署的治理哈希不匹配;留空以使用仅部署者的默认值,或者让两侧保持一致并重新运行构建后。
  • code hashes do not match —— SIMULATED_TEE 与镜像的 MODE 不一致;两者都必须为“真实”(SIMULATED_TEE=false、MODE=0)。
  • ext-proxy 返回 connect: connection refused —— 到 Flare 索引器数据库的 VPN/路由连接中断。
深入排查(专用指南:FCC 故障排查)

大多数故障都是本地技术栈与当前链上部署不一致,或已注册的 URL 现已无法解析所致。在认定是网络问题之前,请先检查以下事项:

  • TEE 始终无法进入生产状态(可用性检查持续返回 404、机器队列为空、getRandomTeeIds 无返回结果、调用方因 TooMany() 回退):首先检查是否正在使用 SIMULATED_TEE=true 运行——模拟证明无法由真实的 Coston2 数据提供方共同签署,因此可用性检查始终不会进入投票流程,机器会永远停留在 INITIALIZED,对它的每次轮询都会返回 404。这是本地开发时的预期行为,并非错误;该机器永远不会在链上显示为 PRODUCTION。除此之外,请通过脚手架的 query-tee 工具读取实际注册的信息——go run ./tools/cmd/query-tee -reg <FlareTeeManager address> <your TEE id>(从 config/coston2/deployed-addresses.json 获取注册表地址,而不要使用工具内置的默认值)。逐字符比较已注册的 url 与当前提供服务的 URL——快速隧道(ngrok/Cloudflare 快速隧道)每次重启都会生成新主机名,因此重启隧道会悄悄导致链上注册失效。请改用命名的 Cloudflare 隧道或预留的 ngrok 域名。query-tee 返回空的 teeId,意味着你连接的部署并非预期中的部署——拉取最新的 main,从 config/coston2/deployed-addresses.json 重新获取所有地址,然后重新运行 pre-build/post-build(重新部署会清除现有注册)。
  • 代理启动时发生 panic,或拒绝 TEE 响应(hex string without 0x prefix、verifying response signature: invalid signature、error signing: could not sign):tee-node 与 tee-proxy 版本不一致——FCC 仍在开发中,它们的线路格式会发生变化。切勿只升级其中一方;Go 模块固定版本和 proxy/Dockerfile 中的 TEE_PROXY_VERSION 必须同步更新。通常,从磁盘上的本地同级目录构建(而不是使用固定版本)会导致版本不一致。
  • 有指令 ID 且没有其他错误,但指令始终无法传到扩展——你可能重复使用了保留的、以 F_ 开头的 OPType,或在自定义 OPType 下使用了上文列出的保留命令名称;这会通过本地成对验证,不会报错,因此指令只会被静默丢弃。
  • 索引器 DB 身份验证/连接失败(Access denied for user 'indexer-reader'、连接 VPN 专用主机时超时)——主机/端口/数据库名称已在上文第 4 步中说明;缺少的只有只读用户名和密码,这些凭据会按请求者单独发放并定期轮换。请通过技术支持或 X申请当前凭据。社区聊天中分享的凭据比文档更容易过期,而且较旧的仓库文档可能指向 Coston(而非 Coston2)索引器;它使用不同的凭据并需要 VPN,Coston2 则不需要。
  • Web2Json 验证器请求仅在访问 Weather Insurance 示例中的 OpenWeatherMap URL 时失败——在认定验证器有问题之前,请检查你的 OpenWeatherMap 套餐。Weather Insurance Extension 示例调用的端点需要付费的 OpenWeatherMap 套餐,因此免费套餐的密钥会在此处失败,即使同一个验证器访问其他 URL 时工作正常。
  • 求助时请提供扩展 ID、TEE 机器地址、失败的指令 ID 和 query-tee 输出——这些信息通常足以立即确定原因。

何时使用其他技能

  • 读取 FTSO 价格馈送、FDC 证明、FAssets 铸造/赎回,或 Smart Accounts — 使用对应的专用技能。
  • 通用网络信息(链 ID、RPC、测试币水龙头、区块浏览器)— 使用 flare-general。

当任务涉及机密/TEE 执行时,请使用此技能:构建或部署扩展、InstructionSender/注册表模式、证明和代码哈希白名单、基于 TEE 的参数化保险,或 fce-extension-scaffold / fce-sign / fce-weather-insurance 仓库。另请参阅 dev.flare.network/fcc,了解官方 Flare Developer Hub 的 FCC 文档。

评论

支持 Markdown