fhevm Host Contracts 实战指南:在宿主链上部署 FHEVM、DAO 升级与跨链 KMS 状态镜像
2026/9/12 19:25:07 网站建设 项目流程

fhevm Host Contracts 实战指南:在宿主链上部署 FHEVM、DAO 升级与跨链 KMS 状态镜像

【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm

本篇指南围绕开源仓库 fhevm 中host-contracts这一 Node 包展开,它承载了在任意宿主 EVM 区块链(Host EVM Blockchain)上部署一套完整 FHEVM 实例所需的全部核心 Solidity 合约。读者将掌握三件事:如何初始化依赖并通过 Forge 运行合约测试;如何以“仅准备不生效”的方式为FHEVMExecutor做 DAO 驱动升级;以及如何理解并操作 Ethereum(canonical 链)与 Polygon 等非 canonical 宿主链之间共享的ProtocolConfig状态——包括镜像方法、导出/审核/应用三步初始化流程。读完本文,你可以独立完成一条非 canonical 宿主链从零初始化、以及后续 KMS 上下文/epoch 轮转的镜像操作。

背景:host-contracts 在 FHEVM 架构中的位置

fhevm 是一个将全同态加密(FHE)能力与区块链应用集成的全栈框架。其中host-contracts(位于仓库根目录下的 host-contracts 目录)专门提供“宿主链侧”的后端合约,其核心职责是:

  • 管理 FHE 密文的访问控制(ACL)与密文输入验证(InputVerifier);
  • 校验 KMS 签名与节点信息(KMSVerifier),并在 canonical 链上执行 KMS 上下文/epoch 的生成与确认(KMSGeneration);
  • 记录协议级配置与 KMS 上下文状态(ProtocolConfig),并负责将该状态跨链同步到非 canonical 宿主链;
  • 承载用户合约执行入口(FHEVMExecutor)与 HCU 资源限制(HCULimit)。

与面向应用开发者的 library-solidity(提供FHE.sol等用户侧库)不同,host-contracts 面向的是链的运营者:谁要部署一条新的 FHEVM 宿主链、谁要升级链上组件、谁要管理多链 KMS 状态,都需要直接与这一层打交道。

快速开始:安装依赖与运行测试

host-contracts同时使用 Hardhat(TypeScript 任务)与 Foundry(Forge 测试)。从仓库根目录进入该包后:

npm install

安装完成后,如果之前未拉取 Soldeer 依赖(如 OpenZeppelin 合约),需要先执行:

npm run forge:soldeer npm run test:forge

对应脚本定义在 host-contracts/package.json 中:forge:soldeer执行forge soldeer installtest:forge执行forge test。包内还提供了常用的 Hardhat 辅助脚本,例如:

  • npm run compile:先部署空的 UUPS 代理(含--with-kms-generation true路径与PauserSet),再执行 hardhat compile;
  • npm run test:运行hardhat test
  • npm run test:gas:仅运行名字匹配Gas的测试用例;
  • npm run mock:daemon/mock:query/mock:encrypt:启动本地 mock coprocessor 守护进程(用于本地链路联调)。

合约清单总览

host-contracts/contracts目录(contracts)下按职责划分为多个子目录与顶层合约:

文件 / 目录职责
ACL.solACLEvents.sol密文访问控制列表及其事件定义,管理谁能对密文执行操作
FHEVMExecutor.sol用户合约执行入口,负责将 FHE 操作调度到 coprocessor 网络
InputVerifier.sol验证 coprocessor 签名的密文输入
KMSVerifier.sol校验 KMS 签名、节点与上下文生命周期信息
KMSGeneration.sol仅在 canonical 宿主链部署,驱动 KMS 上下文/epoch 的生成与确认
ProtocolConfig.sol协议级配置与 KMS 上下文/epoch 状态的唯一事实来源,并提供跨链镜像入口
HCULimit.sol宿主链 HCU(Homomorphic Computation Unit)用量限制
bridge/跨链桥(ConfidentialBridge)相关合约,基于 LayerZero
emptyProxy/immutable/供首次部署与不可变参数使用的辅助代理与不可变合约
interfaces/各合约的接口与事件定义(如IProtocolConfig.sol

本文后续聚焦 README 重点阐述的两个运维主题:FHEVMExecutor 的 DAO 驱动升级ProtocolConfig 的多链状态镜像

Prepare-only executor 升级:DAO 驱动的 FHEVMExecutor 升级

为什么需要“仅准备”模式

FHEVMExecutor是 UUPS 可升级合约,其代理(proxy)地址对用户合约固定不变。常规的task:upgradeFHEVMExecutor会一次性完成“导入代理 → 部署新实现 → 原地升级”。但治理驱动的升级(尤其是 DAO 提案)需要把“部署新实现”和“切换代理”两个动作解耦:先离线准备好实现地址与reinitializeV*调用数据,供多签/DAO 审核签名,再由治理提案最终执行。

task:prepareUpgradeFHEVMExecutor正是为此设计,其行为(定义见 host-contracts/tasks/upgradeContracts.ts)包括:

  • 将现有代理forceImport进 OpenZeppelin 的升级 manifest(使升级校验基于真实部署状态);
  • 通过prepareUpgradekind: 'uups')部署新的实现合约,但不触碰代理
  • 打印新实现地址、reinitializeV*函数签名与 calldata,以及外层upgradeToAndCall(address,bytes)的完整 calldata;
  • 可选地等待 2 分钟后对实现合约执行区块浏览器源码验证。

执行前置条件:地址文件必须与目标环境一致

contracts/FHEVMExecutor.solimportaddresses/FHEVMHostAddresses.sol,把 ACL、KMSVerifier 等兄弟合约地址编译进实现字节码。因此运行升级任务前,磁盘上的地址生成文件必须与当前正在升级的环境一致。若从零生成或切换环境,应按顺序执行以下 setter 任务(顺序很重要:setACLAddress会重写两份文件,其余任务在其基础上追加):

npx hardhat task:setACLAddress --address <acl> npx hardhat task:setFHEVMExecutorAddress --address <executor-proxy> npx hardhat task:setKMSVerifierAddress --address <kms> npx hardhat task:setInputVerifierAddress --address <input-verifier> npx hardhat task:setHCULimitAddress --address <hcu-limit> npx hardhat task:setPauserSetAddress --address <pauser-set>

这些命令生成两份文件:

  • host-contracts/addresses/.env.host
  • host-contracts/addresses/FHEVMHostAddresses.sol

喂给 setter 的地址值应来自当前线上环境的真实部署。一个实用的权威来源是代理背后现有实现合约的已验证源码包(verified source bundle)中的addresses/FHEVMHostAddresses.sol

运行 prepare 任务

npx hardhat task:prepareUpgradeFHEVMExecutor \ --network sepolia \ --current-implementation previous-contracts/FHEVMExecutor.sol:FHEVMExecutor \ --new-implementation contracts/FHEVMExecutor.sol:FHEVMExecutor \ --verify-contract true

参数说明:

  • --network:选择实现合约部署交易发往的链(如 sepolia);
  • --current-implementation:磁盘上保存的旧实现源码路径与合约名(路径:合约名格式);
  • --new-implementation:当前 checkout 中的新实现源码;
  • --use-internal-proxy-address true(可选):代理地址改为从addresses/.env.host读取,而不是从环境变量读取;
  • --verify-contract(默认true):部署完成后等待 2 分钟并对实现执行 Etherscan 类区块浏览器验证。

一个关键实现细节:任务在重新编译前会先执行hardhat clean(见 host-contracts/tasks/upgradeContracts.ts 中compileImplementationscompile:specific的调用及 README 的说明),确保实现不是针对另一环境编译出的过期 artifact 构建的。源码中还会校验新旧实现 artifact 的contractName与预期一致,且新实现必须包含reinitializeV*前缀的重初始化函数,否则直接报错拒绝执行。

与常规升级任务的对比

任务是否修改代理用途
task:upgradeFHEVMExecutor是(立即生效)私钥直接持有者快速升级
task:prepareUpgradeFHEVMExecutor否(仅打印 calldata)DAO 提案:先部署实现、打印upgradeToAndCall载荷供签名

同模式的任务还覆盖ACLKMSVerifierProtocolConfigKMSGenerationInputVerifierHCULimit等全部可升级组件(task:prepareUpgrade*系列),其中ProtocolConfig升级时还会带上由环境变量构建的reinitializeV*参数(buildProtocolConfigReinitializeArgs)。另外首次部署ConfidentialBridgetask:prepareUpgradeConfidentialBridge,其内部调用initializeFromEmptyProxy并校验LZ_ENDPOINT_ADDRESS--dst-eids/--dst-chain-ids配对。

事件消费者注意:KMSVerifier 生命周期事件已迁移

迁移到 canonical 的ProtocolConfig状态之后,KMSVerifier不再发射上下文生命周期事件。链下消费者(如 relayer、listener、KMS-connector)应改从ProtocolConfig合约订阅事件(地址见host-contracts/addresses/FHEVMHostAddresses.sol中的protocolConfigAdd条目):

  • 旧:KMSVerifier.NewContextSet(uint256,address[],uint256)

  • 新:ProtocolConfig.NewKmsContext(uint256,uint256,KmsNodeParams[],KmsThresholds,string,PcrValues[])

  • 旧:KMSVerifier.KMSContextDestroyed(uint256)

  • 新:ProtocolConfig.KmsContextDestroyed(uint256)

新事件签名与 host-contracts/contracts/interfaces/IProtocolConfig.sol 中定义一致,额外携带 epochId、节点参数、阈值、软件版本与 PCR 值,信息量比旧事件更完整。

宿主部署角色:canonical 与非 canonical

task:deployAllHostContracts强制要求显式传入--with-kms-generation取值,以明确本次部署的宿主链角色:

npx hardhat task:deployAllHostContracts --with-kms-generation true # canonical 宿主链 npx hardhat task:deployAllHostContracts --with-kms-generation false # 非 canonical 宿主链

同一份合约,多条链:canonical 是唯一事实来源

Ethereum 是 canonical 宿主链——KMS 上下文/epoch 状态的唯一事实来源,完整的生命周期只在其上运行:治理方开启一个上下文/epoch(defineNewKmsContextAndEpoch/defineNewEpochForCurrentKmsContext),KMS 签名者达成法定人数(confirmKmsContextCreation/confirmEpochActivation)后状态才激活。KMSGeneration只部署在 Ethereum 上。

其他每条宿主链上部署的是同一份ProtocolConfig合约(不存在单独的"多链合约"),但这些非 canonical 宿主链(如 Polygon)是只读副本(read-replica):它们不运行生命周期/法定人数路径,因为 KMS 重分片与远程证明只在 Ethereum 上发生一次。它们没有KMSGeneration,唯一的写入路径就是下文介绍的镜像方法。

镜像方法:非 canonical 链的写入路径

mirrorKmsContextAndEpochmirrorKmsEpoch是副本(replica)追踪 Ethereum 状态的方式。两者都是onlyACLOwner绕过确认法定人数——副本无法重跑 MPC 远程证明,因此信任运营者导入 Ethereum 已最终确定的状态,并使其立即变为Active

合约侧实现(host-contracts/contracts/ProtocolConfig.sol):

  • mirrorKmsContextAndEpoch(contextId, epochId, kmsNodeParams, thresholds, softwareVersion, pcrValues)——导入一个上下文及其首个 epoch 为 active 状态,发射MirrorKmsContextAndEpoch事件。内部先校验contextId > latestActiveKmsContextId(否则 revertNonIncreasingKmsContextId)、epochId > epochCounter(否则 revertNonIncreasingEpochId),再_storeAndActivateKmsContextAndEpoch落库。
  • mirrorKmsEpoch(contextId, epochId)——推进已镜像上下文的 active epoch,发射MirrorKmsEpoch事件。要求contextId等于当前 active 上下文且该上下文仍存活,epoch 同样必须严格递增。

严格递增:唯一的链上防回滚守卫

ID 必须严格递增——这是唯一的链上守卫,防止状态回滚。间隔(gap)是允许的:在 Ethereum 上被中止或从未激活的上下文/epoch 只是永远不会被镜像而已。但没有任何机制阻止副本漂移:如果一次镜像调用被跳过或乱序应用,副本状态就会落后。按序将 Ethereum 的每次轮转回放到每个副本,是运营者的责任。

任务层(定义在 host-contracts/tasks/mirrorKmsContext.ts)提供了两组镜像任务,均遵循“build calldata(DAO 路径,从不广播)/ broadcast(devnet / test-suite 无 DAO 路径)”的约定:

  • 上下文切换:task:buildMirrorKmsContextAndEpochCalldata/task:mirrorKmsContextAndEpoch
  • 同节点集 epoch 轮转:task:buildMirrorKmsEpochCalldata/task:mirrorKmsEpoch

这四者共享同一组 CLI 参数:--canonical-rpc-url(canonical 链 RPC)、--canonical-protocol-config-address、可选的--block-number(默认读取 latest finalized 区块)与可选的--use-internal-proxy-address

上下文切换路径有一个额外的安全校验:它从 canonical 读取 active 上下文锚(getKmsContextAnchor)定位NewKmsContext事件的发射区块,读取该事件中的节点/软件版本/PCR 数据后,用 ABI 编码重新计算contextInfoHash并与链上锚比对;不一致直接抛错(tasks/mirrorKmsContext.tsreadCanonicalContextSwitchcomputeContextInfoHash与哈希比对)。事件数据在 ETH 上不存在(MPC 字段不在存储内),因此节点数据只能从事件取回,这个哈希交叉校验保证了事件数据与链上锚一致。广播前还会断言副本确实需要切换/推进(assertReplicaNeedsContextSwitch/assertReplicaNeedsEpochMirror),给出明确的错误信息而不是裸 revert。

从 canonical 链初始化非 canonical 的 ProtocolConfig

Ethereum 的ProtocolConfig是协议状态的唯一事实来源,因此新的宿主链要从它播种副本。整个流程是 artifact 驱动的——每个环境都走同样的三步。

第 1 步:导出 canonical KMS 上下文为可审核的 JSON artifact

该步骤只需 RPC 访问,可从干净的 checkout 直接运行:

npx hardhat task:exportCanonicalProtocolConfig \ --canonical-rpc-url https://mainnet.example \ --canonical-protocol-config-address 0x... \ --out canonical-protocol-config-snapshot.json

artifact 持有一个export对象:它是将快照展开为扁平KEY=value映射,bigint 序列化为十进制字符串。每个 key 会成为第 3 步 apply 任务读取的环境变量。其底层实现在 host-contracts/tasks/protocolConfigMirror.ts 的readCanonicalSnapshot:先做 RPC 握手(getNetwork+getBlock,默认钉在finalized区块),再做合约身份/版本前缀校验,随后一次性读取 active 上下文/epoch、节点集与四个阈值。

第 2 步:审核

所有读取都发生在同一个区块上,因此审核者(如 DAO 签名者)可以通过重新运行带--block-number <N>的导出并 diff 输出,逐字节复现artifact——即使之后发生了defineNewKmsContextAndEpoch轮转也不受影响。

第 3 步:应用

将审核通过的 artifact 应用到本地的ProtocolConfig代理上。两种环境运行相同的 prepare 步骤——部署实现并构建upgradeToAndCall(initializeFromCanonical(contextId, epochId, …))载荷,让副本落在 canonical 的 active 上下文/epoch 上,而不是从本地新计数器开始。两者的差异仅在谁执行该载荷:

环境任务签名者
devnet / localtask:deployProtocolConfigFromCanonicalDEPLOYER_PRIVATE_KEY
testnet / mainnettask:prepareDeployProtocolConfigFromCanonicalDAO 执行打印出的upgradeToAndCall载荷
# devnet:用部署者私钥直接升级 npx hardhat task:deployProtocolConfigFromCanonical # testnet/mainnet:部署实现并打印 DAO 载荷,不触碰代理 npx hardhat task:prepareDeployProtocolConfigFromCanonical

导出 key 对照表

两个 apply 任务都从环境变量读取配置,不接受任何命令行 flag传入 canonical 状态——由部署平台把值注入部署容器。任务会在部署任何东西之前拒绝坏值,因此配置错误的环境不会动到代理。导出 key 如下:

Variable类型含义
CANONICAL_CHAIN_IDdecimal stringcanonical 宿主链的 chain id。
CANONICAL_PROTOCOL_CONFIG_ADDRESSaddress快照读取自的 canonicalProtocolConfig地址。
CANONICAL_BLOCK_NUMBERdecimal string快照钉住的区块号。
CANONICAL_BLOCK_HASH32-byte hex该区块的哈希。
CANONICAL_KMS_CONTEXT_IDdecimal string要镜像的 active KMS context id。
CANONICAL_EPOCH_IDdecimal string要镜像的 active KMS epoch id。
CANONICAL_KMS_NODESJSON arrayKMS 节点集,每个节点一个 JSON 对象。
CANONICAL_KMS_THRESHOLDSJSON object四个阈值,每个为 decimal string。

context id、epoch id、节点集与阈值会成为initializeFromCanonical的 calldata,因此任务会对它们完整校验。chain id 与区块号属于溯源信息,任务按十进制字符串解析。区块哈希与地址同样是溯源信息,任务只检查存在性并打印。

合约侧的initializeFromCanonical(host-contracts/contracts/ProtocolConfig.sol)带有onlyFromEmptyProxyreinitializer守卫,并校验canonicalContextId >= KMS_CONTEXT_COUNTER_BASE + 1canonicalEpochId >= EPOCH_COUNTER_BASE + 1,随后_storeAndActivateKmsContextAndEpoch一次性落库并激活。注意该函数只接收四个入参(contextId、epochId、节点、阈值):MPC 元数据(partyId、mpcIdentity、caCert、storagePrefix)不会被存储,因此镜像路径用确定性占位符填充(partyId从 0 编号、mpcIdentity为空串、caCert0xstoragePrefix为空串),见buildCanonicalUpgradeProposal中的注释说明——副本存储的节点集仍与 canonical 完全一致。

职责边界:任务只校验“环境给了什么”

只有第 1 步会访问 canonical 链。任务只检查环境变量给它们的值,不会证明这些值与审核过的 artifact 一致——这个绑定关系由部署平台负责。两个 apply 任务都会打印decodedArgs(载荷编码的 context id、epoch id、节点集与阈值),以及 chain id、区块号、区块哈希与 canonicalProtocolConfig地址。运营者需要把每个溯源值与 artifact 逐一比对;由于打印的节点集带占位 MPC 字段,需逐字段比对。

全栈部署与后续轮转

部署一整套非 canonical 宿主栈时,task:deployAllHostContracts --protocol-config-source canonical会把镜像与其余宿主合约串行执行,使用相同的环境变量(fhevm-cli 多链栈正是如此,因此 e2e 测试用与生产完全相同的方式播种非 canonical 链)。

后续的 canonical 轮转则分别用:

  • task:buildMirrorKmsContextAndEpochCalldata/task:mirrorKmsContextAndEpoch——上下文切换(更换签名者集合);
  • task:buildMirrorKmsEpochCalldata/task:mirrorKmsEpoch——同节点集 epoch 轮转。

两者都通过--canonical-rpc-url/--canonical-protocol-config-address读取 canonical 的 active KMS 上下文/epoch(上下文切换对还会用恢复出的NewKmsContext事件数据与 canonical 的contextInfoHash锚交叉校验),然后调用副本的mirrorKmsContextAndEpoch/mirrorKmsEpoch(定义于 host-contracts/tasks/mirrorKmsContext.ts)。

小结:一张图看懂状态流

Ethereum(canonical)侧:治理defineNewKmsContextAndEpoch→ KMS 签名者confirmKmsContextCreation/confirmEpochActivation→ 状态ActiveNewKmsContext/KmsContextDestroyed事件由ProtocolConfig发射。非 canonical 侧:mirrorKmsContextAndEpoch/mirrorKmsEpochonlyACLOwner、严格递增、跳过法定人数)直接把 Ethereum 已确定的状态导入为Active,发射MirrorKmsContextAndEpoch/MirrorKmsEpoch。新增宿主链则通过“导出 → 审核 → 应用”三步,以initializeFromCanonical直接播种 canonical 的 active 状态。

这套设计把多签共识集中到一条链上(MPC 重分片与远程证明只跑一次),其余宿主链只消费结果;代价是副本的最终一致性完全依赖运营者按序回放每一次轮转。理解“canonical 是唯一事实来源、副本是受信任的镜像”这一心智模型,是正确运维多链 FHEVM 的关键。

【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询