news 2026/9/12 15:49:37

fhEVM Coprocessor 链上升级实操:借助 Aragon DAO 完成 `proposeCoprocessorUpgrade` 提案的全流程指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
fhEVM Coprocessor 链上升级实操:借助 Aragon DAO 完成 `proposeCoprocessorUpgrade` 提案的全流程指南

fhEVM Coprocessor 链上升级实操:借助 Aragon DAO 完成proposeCoprocessorUpgrade提案的全流程指南

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

本篇指南完整讲解 fhEVM 仓库中 coprocessor(协处理器)需要链上升级提案时的标准操作流程:如何通过 GitHub Actions 工作流或 Hardhat 任务,为 Aragon DAO 生成调用ProtocolConfig.proposeCoprocessorUpgrade(...)的 calldata,并在 DAO 投票通过后打开覆盖所有 host 链与 gateway 的升级窗口。读完本文,你将掌握从环境参数确认、跨链区块窗口计算、calldata 获取到 DAO 提案提交与本地演练的完整实战能力,并能理解底层源码的窗口投影与 buffer 校验逻辑。

原始操作手册位于 host-contracts/COPROCESSOR_UPGRADE_RUNBOOK.md,本文以其为骨架,结合 host-contracts/tasks 下的实现源码与测试进行纵深展开。

一、升级提案的背景与产出

fhEVM 的 coprocessor 是链下负责同态加密计算(TFHE 运算、解密等)的分布式服务。当 coprocessor 需要发布新版本(例如v0.14.0)时,出于安全与可审计性要求,升级必须经过链上治理:由 Aragon DAO 对ProtocolConfig.proposeCoprocessorUpgrade(...)进行投票,投票通过后升级窗口才会在所有 host 链与 gateway 上打开,GCS(Gateway Coprocessor Service)等相关组件才能在该窗口内完成蓝绿切换与回放(dry-run)。

本流程产出物是一个十六进制字符串(calldata),它对应 Aragon DAO 提案中调用的ProtocolConfig.proposeCoprocessorUpgrade(...)动作。DAO 投票通过并执行提案后,链上会发出CoprocessorUpgradeProposed事件,升级窗口随即开启。

从合约源码看,host-contracts/contracts/ProtocolConfig.sol 中的proposeCoprocessorUpgrade方法签名如下:

function proposeCoprocessorUpgrade( uint256 proposalId, string calldata softwareVersion, ChainUpgradeWindow[] calldata chainUpgradeWindows, uint64 gwStartBlock ) external virtual onlyACLOwner

其中每个链的升级窗口使用 host-contracts/contracts/shared/Structs.sol 中定义的ChainUpgradeWindow结构:

struct ChainUpgradeWindow { uint64 chainId; // 该窗口适用的 host 链 ID uint64 startBlock; // GCS 在 dry-run 中回放的首个区块(含) uint64 endBlock; // GCS 在 dry-run 中回放的最后一个区块(含) }

该结构体注释明确说明其用途是"coprocessor blue-green upgrade"期间每个 host 链的回放窗口,这解释了为什么提案需要为每一条链精确计算起止区块号。

二、前置条件

在运行任何工具之前,请确认以下条件已满足:

  • 新版本已构建完成:新的 coprocessor 版本已经构建好,并已知其发布标签(release tag),例如v0.14.0
  • dry-run 评估窗口的起始墙钟时间已确定:评估窗口的 wall-clock 开始时间已经最终确认,并以 ISO 8601 UTC 格式记录。
  • 起始时间足够靠后:开始时间必须给 DAO 投票留出足够的前置时间,这个前置时间即--buffer参数,主网通常取2h。如果起始区块距离当前链头太近,任务会因 buffer 校验失败而拒绝输出(见下文"buffer 门禁")。

三、Step 1 — 运行 GitHub Actions 工作流

仓库提供了名为host-contracts-prepare-coprocessor-upgrade的手动触发工作流(.github/workflows/host-contracts-prepare-coprocessor-upgrade.yml),它针对所选环境的真实 RPC 执行task:prepareCoprocessorUpgrade任务,并把计算报告与 ABI 编码后的 calldata 输出到工作流日志。

在仓库页面进入Actions → host-contracts-prepare-coprocessor-upgrade → Run workflow,填写以下输入:

输入项取值说明
Environmentdevnettestnetmainnet目标环境,下拉选择
Start timeISO 8601 UTC,例如2026-07-01T12:00:00Z评估窗口的墙钟开始时间
Duration窗口长度,例如30m支持30s30m2h1d或裸整数秒
BufferDAO 前置时间,例如2h从"现在"到startBlock之间必须保留的秒数
Proposal id任意正整数(运营方自选)合约会拒绝0
Software versioncoprocessor 发布标签,例如v0.14.0随提案上链的版本字符串

点击Run workflow并等待任务完成。

工作流的内部实现值得注意两点(来源:.github/workflows/host-contracts-prepare-coprocessor-upgrade.yml):

  • 所有 RPC 密钥通过env:注入,而不是在run:中插值,以防止workflow_dispatch输入造成 shell 注入;
  • 工作流把所有环境的 RPC secrets 无条件注入(RPC_URL_ETHEREUMRPC_URL_POLYGONRPC_URL_SEPOLIARPC_URL_AMOYRPC_URL_GATEWAY_DEVNETRPC_URL_GATEWAY_TESTNETRPC_URL_GATEWAY_MAINNET),脚本只读取所选环境需要的那些,因此某个环境缺失 secret 会以env var RPC_URL_X is not set报错(见下文"失败模式")。

四、Step 2 — 复制 calldata

工作流完成后,打开"Prepare upgrade proposal"步骤的日志,滚动到末尾。在## Calldata标题下的最后一块内容即是以0xccbf8199…开头的十六进制字符串。

0xccbf8199proposeCoprocessorUpgrade函数的函数选择器(前 4 字节),其 ABI 定义内联在 host-contracts/tasks/utils/coprocessorUpgradeProposal.ts 中:

function proposeCoprocessorUpgrade(uint256 proposalId, string softwareVersion, tuple(uint64 chainId, uint64 startBlock, uint64 endBlock)[] chainUpgradeWindows, uint64 gwStartBlock)

请复制整个十六进制字符串(不要只复制选择器),它将在 Step 3 中作为 DAO 提案的 calldata 使用。

五、Step 3 — 提交 DAO 提案

打开目标环境对应的 Aragon DAO:

  • Mainnet— Ethereum 上的 Aragon DAO:0xB6D69D5F334d8B97B194617B53c6aB62f8681Ef3
  • Testnet— Sepolia 上的 Aragon DAO:0x08e8a84c3c8c7cba165B1adcf67Ae4639eF84f52

在 DAO 中创建新提案,填写:

  • Target contract:host 链上的ProtocolConfig合约(mainnet 为 Ethereum 上的部署,testnet 为 Sepolia 上的部署);
  • Calldata:Step 2 中复制的十六进制字符串。

DAO 投票通过且提案执行后,链上proposeCoprocessorUpgrade事件触发,升级窗口在所有 host 链与 gateway 上打开。注意该方法是onlyACLOwner限定的(host-contracts/contracts/ProtocolConfig.sol),即只有 ACL 所有者(即 DAO 地址)能够成功调用,这正是必须经由 DAO 提案的原因。

六、升级窗口的生成原理:从墙钟时间到区块号

工作流和 Hardhat 任务的核心逻辑都在 host-contracts/tasks/utils/blockWindow.ts 中,理解它能帮助你正确设置--start-time--duration

6.1 区块时间采样

sampleBlockTime读取链头区块号与时间戳,再向前回溯采样BLOCK_TIME_SAMPLE_SIZE = 1000个区块(host-contracts/tasks/utils/blockWindow.ts),用"采样起止时间差 ÷ 区块数"估算平均出块时间。如果链太年轻(不足 1000 个区块)或采样失败,则回退到该环境配置的fallbackBlockTimeSeconds(并在报告中标记usedFallback/WARN: block-time sampling failed)。

6.2 区块号投影

projectBlockNumber以链头为基准,把目标墙钟时刻投影为区块号:

deltaSeconds = targetTimestamp - tipTimestamp projectedBlock = tipBlock + round(deltaSeconds / blockTimeSeconds)

由于按"最近的区块"取整,投影产生的 skew 被限定在半块出块时间以内——报告中会以startSkewSeconds明确展示这一误差(host-contracts/tasks/utils/blockWindow.ts)。

6.3 buffer 门禁(DAO 投票缓冲)

bufferSatisfied校验startBlock与链头之间按有效出块时间换算出的墙钟间隔是否 ≥--buffer(host-contracts/tasks/utils/blockWindow.ts)。若任一 host 链或 gateway 不满足,任务会硬性失败(DAO 路径打印 calldata 供检查但明确提示"不得提交";直连路径直接拒绝广播)。

报告中还会输出跨链对齐信息:所有 host 链与 gateway 的startBlock估计时间戳的最大跨度(start skew range)以及各自相对最早起点的延迟,便于运营方判断窗口是否足够对齐。

6.4 出块时间漂移告警

如果采样得到的真实出块时间与配置的 fallback 相差超过 20%(BLOCK_TIME_DRIFT_WARN_FRACTION = 0.2),报告会给出WARN: observed block time drifted >20% from fallback提示,警示当前网络可能处于拥堵状态,窗口估算应谨慎对待(host-contracts/tasks/utils/blockWindow.ts)。

七、环境与链集合参考

每个环境的链 ID、出块时间与 RPC 环境变量名统一登记在 host-contracts/tasks/utils/environments.ts 的ENVIRONMENTS注册表中:

环境链(chainId)fallback 出块时间RPC 环境变量公共默认 RPC
devnetsepolia1115511112sRPC_URL_SEPOLIAhttps://ethereum-sepolia-rpc.publicnode.com
devnetamoy800021.5sRPC_URL_AMOYhttps://rpc-amoy.polygon.technology
devnetgateway-devnet2sRPC_URL_GATEWAY_DEVNET无(内部端点,必须设置)
testnetsepolia1115511112sRPC_URL_SEPOLIA同上公共端点
testnetamoy800021.5sRPC_URL_AMOY同上公共端点
testnetgateway-testnet2sRPC_URL_GATEWAY_TESTNEThttps://rpc.testnet.zama.org
mainnetethereum112sRPC_URL_ETHEREUM无(生产 RPC 私有,必须设置)
mainnetpolygon1372sRPC_URL_POLYGON无(生产 RPC 私有,必须设置)
mainnetgateway-mainnet2sRPC_URL_GATEWAY_MAINNET无(生产 RPC 私有,必须设置)

从源码注释可以确认设计原则:defaultRpcUrl仅保留给公开、众所周知的端点(如测试网公共 RPC),主网端点和任何私有/内部 URL 必须省略defaultRpcUrl,强制运营方通过 repo secrets 配置,防止密钥泄露或误连公共限流端点。

新增链的方式:向目标环境的chains数组追加条目;新增环境则添加顶层键并给出chains+gateway。注册表在模块加载时校验同一环境内chainId唯一,重复会直接抛错。

八、合约层的输入校验

即使 calldata 已生成并提交,ProtocolConfig.proposeCoprocessorUpgrade在执行时还会做一套完整的链上校验(host-contracts/contracts/ProtocolConfig.sol):

  • proposalId == 0→ 拒绝(InvalidProposalId);
  • softwareVersion为空 → 拒绝(EmptySoftwareVersion);
  • chainUpgradeWindows为空数组 → 拒绝(EmptyChainUpgradeWindows);
  • gwStartBlock == 0→ 拒绝(ZeroGwStartBlock);
  • 任一chainId == 0→ 拒绝(ZeroChainId);
  • 任一startBlock > endBlock→ 拒绝(InvalidBlockWindow);
  • 出现重复chainId→ 拒绝(DuplicateChainId)。

全部校验通过后才发出CoprocessorUpgradeProposed(proposalId, softwareVersion, chainUpgradeWindows, gwStartBlock)事件。这也解释了为什么运营方选择的--proposal-id必须是正整数、且--duration不能过短——校验在链下任务与链上合约两个层面同时生效。

九、失败模式与排障

运行工作流或任务时可能遇到以下日志错误,对应的处理方法如下:

日志中的错误处理方法
DAO buffer violated for: chain X — short by 22m--start-time至少再向后推迟所缺的时长后重跑。
env var RPC_URL_X is not set在 repo settings 中补齐缺失的 secret;工作流文件头部按环境列出了所需 secrets。
--environment must be one of: devnet, testnet, mainnet从下拉框中选择一个合法环境。
duration too short for chain block time至少使用1m作为--duration(该错误由 host-contracts/tasks/utils/blockWindow.ts 在投影出的endBlock <= startBlock时抛出)。

此外还有两类非致命告警需要留意:block-time sampling failed; used configured fallback(采样失败回退到配置值)与block-time drifted >20% from fallback(网络拥堵,出块时间与配置偏差过大)。

十、本地演练(DAO 路径)

在本地做 dry-run 或开发调试时,可以直接运行task:prepareCoprocessorUpgradeHardhat 任务(定义在 host-contracts/tasks/prepareCoprocessorUpgrade.ts),它只计算并打印 calldata,绝不广播交易

cd host-contracts npx hardhat task:prepareCoprocessorUpgrade \ --environment testnet \ --start-time "$(date -u -v+2H '+%Y-%m-%dT%H:%M:%SZ')" \ --duration 30m \ --buffer 1h \ --proposal-id 1 \ --software-version v0.14.0

输出与 calldata 和工作流运行完全一致。如果任何链的startBlock距离链头小于--buffer,任务会以非零退出码失败,并打印 calldata 供检查(但明确提示不得提交)。可用以下命令查看完整参数说明:

npx hardhat help task:prepareCoprocessorUpgrade

任务底层调用链为:parseCoprocessorUpgradeInputs(校验并解析输入、解析 RPC URL)→buildCoprocessorUpgradeProposal(调用computeBlockWindow逐链/逐 gateway 计算窗口)→encodeProposeCoprocessorUpgrade(纯 ABI 编码)→printCoprocessorUpgradeProposal(打印报告与 calldata)→bufferViolations(buffer 门禁判定),全部实现在 host-contracts/tasks/utils/coprocessorUpgradeProposal.ts。

时间与时长参数的解析规则(host-contracts/tasks/utils/blockWindow.ts):

  • 时间戳:ISO 8601 UTC,如2026-07-01T12:00:00Z
  • 时长:30s/30m/2h/1d或裸整数(按秒解释);
  • --proposal-id支持十进制或0x十六进制,且必须 > 0。

十一、直连(no-DAO)路径 — devnet / test-suite

在 devnet 或 test-suite 环境中,deployer 密钥拥有 host 链上的ProtocolConfig(即onlyACLOwner的 owner 是 deployer),因此可以跳过 DAO,直接把 calldata 广播上链。task:proposeCoprocessorUpgrade执行相同的构建步骤,然后用DEPLOYER_PRIVATE_KEY发送字节完全一致的 calldata——它是 KMS 上下文切换任务task:defineNewKmsContextAndEpoch广播路径的姊妹实现。

它发送到--network指定网络上的 hostProtocolConfig;合约地址可通过环境变量PROTOCOL_CONFIG_CONTRACT_ADDRESS指定,或加--use-internal-proxy-addressaddresses/目录读取:

cd host-contracts DEPLOYER_PRIVATE_KEY=0x... npx hardhat --network sepolia task:proposeCoprocessorUpgrade \ --environment devnet \ --start-time "$(date -u -v+2H '+%Y-%m-%dT%H:%M:%SZ')" \ --duration 30m --buffer 1h --proposal-id 1 --software-version v0.14.0 \ --use-internal-proxy-address

广播前同样会执行 buffer 门禁:若任一链不满足 buffer,任务直接拒绝广播(Refusing to broadcast)。广播实现位于executeCoprocessorUpgradeProposal(host-contracts/tasks/utils/coprocessorUpgradeProposal.ts),它用 deployer 钱包向目标地址发送{ to: target, data: calldata }并等待交易确认后返回交易哈希。

十二、测试与验证

仓库为这套逻辑提供了针对非 RPC 面的单元测试(host-contracts/test/tasks/prepareCoprocessorUpgrade.ts),覆盖:

  • 编码往返encodeProposeCoprocessorUpgrade生成的 calldata 能被PROPOSE_UPGRADE_ABI解码还原出完全一致的proposalIdsoftwareVersion与各链窗口(含 sepolia、amoy 两条链与 gateway);
  • 输入校验parseCoprocessorUpgradeInputs对非法--proposal-id(非整数、≤ 0)与空--software-version的拒绝行为;
  • buffer 门禁bufferViolations正确列出不满足 buffer 的链与 gateway。

窗口计算本身依赖真实 RPC(由工作流覆盖),因此测试刻意避开 RPC,只验证与网络无关的纯逻辑面。合约层的CoprocessorUpgradeProposed事件与各类 revert 分支的完整行为,可在 host-contracts/test/protocolConfig/protocolConfig.t.sol 中找到对应用例,可作为理解链上校验的补充阅读材料。

结语

coprocessor 升级是 fhEVM 多链体系中的关键治理动作:它把"新版本发布"与"多链+gateway 同步切换"通过 Aragon DAO 提案串成一条可审计、可回放的闭环。掌握本 runbook 的四个要点——正确设置时间参数(start-time/duration/buffer)、理解区块窗口的投影与 buffer 门禁、区分 DAO 路径与 no-DAO 路径、善用本地演练与排障表——即可安全、可重复地完成每一次 coprocessor 链上升级。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 15:47:36

Java多线程计时器原理与优化实践

1. 多线程计时器项目概述在Java并发编程中&#xff0c;计时器(Timer)是一个经典的多线程应用场景。这个看似简单的功能背后&#xff0c;涉及线程调度、任务队列、同步控制等多个核心技术点。我见过不少初级开发者直接使用Java内置的Timer类&#xff0c;却说不清楚其内部工作原理…

作者头像 李华
网站建设 2026/9/12 15:47:27

微弱信号检测的自相关法:原理、Python实现与工程要点

简介&#xff1a;针对通信、雷达等系统中微弱信号易被强噪声淹没的难点&#xff0c;这份MATLAB代码包给出基于自相关法的检测实现思路。自相关法利用信号与其时间延迟副本的统计相关性来区分周期信号与随机噪声&#xff0c;适合在低信噪比环境下提取信号特征。包内共2个m文件&a…

作者头像 李华
网站建设 2026/9/12 15:43:51

500 个 AI Agent 行业落地案例:5 分钟跑通你的第一个智能体

500 个 AI Agent 行业落地案例&#xff1a;5 分钟跑通你的第一个智能体 【免费下载链接】500-AI-Agents-Projects The 500 AI Agents Projects is a curated collection of AI agent use cases across various industries. It showcases practical applications and provides l…

作者头像 李华