fhevm 网关暂停机制环境变量完全指南:PAUSER_PRIVATE_KEY 与 DEPLOYER_PRIVATE_KEY 的配置与使用
【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm
本文是 fhevm 开源仓库中 Gateway 网关合约「暂停机制」的环境变量配置指南。文章以 gateway-contracts/docs/getting-started/pausing/env_variables.md 为骨架,结合 pauseContracts.ts、Pausable.sol、GatewayConfig.sol 及 .env.example 等仓库源码与配置,系统讲解暂停/恢复网关所需的两个核心环境变量、它们的来源、被哪些 Hardhat 任务消费,以及底层合约如何校验调用者身份。读完本文,你将能够正确配置本地与生产环境的暂停相关变量,并理解暂停权限与所有权转移之间的安全边界。
为什么暂停机制需要专门的环境变量
fhevm Gateway 协议允许「暂停者(pauser)」在紧急情况下暂停网关合约,阻止新的请求(输入证明、解密请求)被处理;网关只能被手动暂停和恢复。暂停能力由PauserSet(管理暂停者地址)与抽象合约Pausable(提供暂停/恢复功能)共同支撑,详见 暂停机制文档 与 PauserSet 合约文档。
暂停操作由 Hardhat 任务驱动(见下文),而任务执行时需要签名账户,因此仓库约定通过两个环境变量注入密钥:
| 环境变量 | 说明 | Solidity 类型 | 默认值 | 备注 |
|---|---|---|---|---|
PAUSER_PRIVATE_KEY | 某个暂停者的私钥 | bytes32 | - | - |
DEPLOYER_PRIVATE_KEY | 部署者的私钥 | bytes32 | - | - |
这两个变量的取值示例均来自 .env.example,用于本地测试;其中列出的账户都是通过以下命令生成的、已注资的 Hardhat 账户:
make get-accounts该命令定义在 Makefile 中,实际执行的是DOTENV_CONFIG_PATH=$(ENV_PATH) npx hardhat get-accounts,即以.env中的助记词批量推导账户地址与私钥。
PAUSER_PRIVATE_KEY:暂停者私钥
PAUSER_PRIVATE_KEY="0x3588ffb4f4d9bea785a012b895543fe68f2d580a9d449decc91a25878064079a" # (bytes32)暂停者私钥是注册在PauserSet合约中的某个暂停者地址所对应的私钥。它被用于通过暂停类 Hardhat 任务暂停合约,包括pauseAllGatewayContracts。每个运营商(operator)都应将该环境变量设置为自己的热钱包(hot wallet)中用作暂停者的账户私钥。
在 .env.example 中的来源与对应关系
在 .env.example 中,暂停者相关配置如下:
# Pausers # The number of pausers must be lower or equal to the number of pausers' address defined below NUM_PAUSERS="2" # Pauser 1 PAUSER_ADDRESS_0="0x6591319B97979Acc59b7191A8B4Ec381375bFc92" # accounts[23] (address) # Pauser 2 PAUSER_ADDRESS_1="0xb19e21437c47A541842bB84b018d3955462B35De" # accounts[24] (address) # The first pauser's private key # This is required for local tests and running the pausing task. It must correspond to one of the pauser's private key PAUSER_PRIVATE_KEY="0x3588ffb4f4d9bea785a012b895543fe68f2d580a9d449decc91a25878064079a" # accounts[23], private key (bytes32)关键对应关系:PAUSER_PRIVATE_KEY必须与PAUSER_ADDRESS_0(即accounts[23])匹配。注释明确说明它"必须对应于某个暂停者的私钥"。本地测试时,.env.example 还提供了NUM_PAUSERS、PAUSER_ADDRESS_{i}等注册信息,用于把暂停者地址写入PauserSet合约。
暂停者数量与运营商的关系
按照 部署环境变量文档 的说明,NUM_PAUSERS(注册的暂停者数量)应等于协议中注册的运营商总数(KMS 节点数量 + 协处理器数量)。每个暂停者预期是协议运营商控制的热钱包,PauserSet合约提供addPauser、removePauser、swapPauser与isPauser四个函数来管理这些地址(见 PauserSet 合约文档)。
DEPLOYER_PRIVATE_KEY:部署者私钥
DEPLOYER_PRIVATE_KEY="0x7136d8dc72f873124f4eded25f3525a20f6cee4296564c76b44f1d582c57640f" # (bytes32)这是部署者账户的私钥,用于部署合约(详见 部署环境变量文档)。如果GatewayConfig合约的所有权由部署者持有,则它还可用于恢复(unpause)被暂停的合约(详见 暂停机制文档)。
在 .env.example 中,DEPLOYER_PRIVATE_KEY对应accounts[1]:
# Private keys DEPLOYER_PRIVATE_KEY="0x7136d8dc72f873124f4eded25f3525a20f6cee4296564c76b44f1d582c57640f" # accounts[1], private key (bytes32) NEW_OWNER_PRIVATE_KEY="0x7ae52cf0d3011ef7fecbe22d9537aeda1a9e42a0596e8def5d49970eb59e7a40" # accounts[2], private key (bytes32)两个变量如何驱动暂停/恢复任务
暂停与恢复操作通过 pauseContracts.ts 中定义的 Hardhat 任务完成。该文件是理解这两个环境变量如何被消费的最佳源码入口。
暂停类任务
task:pauseAllGatewayContracts:暂停全部网关合约task:pauseInputVerification:仅暂停InputVerification合约task:pauseDecryption:仅暂停Decryption合约
这些任务需要本地设置PAUSER_PRIVATE_KEY环境变量。
恢复类任务
task:unpauseAllGatewayContracts:恢复全部网关合约task:unpauseInputVerification:仅恢复InputVerification合约task:unpauseDecryption:仅恢复Decryption合约
重要限制:这些恢复任务只有在GatewayConfig合约的所有权由部署者持有时才能执行,因此要求本地设置DEPLOYER_PRIVATE_KEY。一旦GatewayConfig的所有权转移到多签(multi-sig)所有者,这些任务将无法再恢复合约;届时必须通过多签合约调用GatewayConfig的unpause函数来恢复。
源码层面的密钥注入逻辑
在 pauseContracts.ts 中,getGatewayContract辅助函数通过getRequiredEnvVar(envVarPrivateKeyName)读取对应的环境变量,并用它构造签名钱包:
async function getGatewayContract( name: string, ethers: HardhatEthersHelpers, useInternalAddress: boolean, envVarPrivateKeyName: string, ) { // Get the account (pauser for pausing OR deployer for unpausing) wallet const accountPrivateKey = getRequiredEnvVar(envVarPrivateKeyName); const account = new Wallet(accountPrivateKey).connect(ethers.provider); ... }暂停单个合约时传入'PAUSER_PRIVATE_KEY',恢复单个合约时传入'DEPLOYER_PRIVATE_KEY':
async function pauseSingleContract(name: string, ethers: HardhatEthersHelpers, useInternalAddress: boolean) { const { contract, proxyAddress } = await getGatewayContract(name, ethers, useInternalAddress, 'PAUSER_PRIVATE_KEY'); await contract.pause(); console.log(`${name} contract successfully paused at address: ${proxyAddress}\n`); } async function unpauseSingleContract(name: string, ethers: HardhatEthersHelpers, useInternalAddress: boolean) { // NOTE: this task won't work once ownership will be transferred from initial deployer to the multisig const { contract, proxyAddress } = await getGatewayContract(name, ethers, useInternalAddress, 'DEPLOYER_PRIVATE_KEY'); await contract.unpause(); console.log(`${name} contract successfully unpaused at address: ${proxyAddress}\n`); }getRequiredEnvVar定义于 loadVariables.ts,若对应环境变量缺失会直接抛错,从而保证任务不会被错误地静默执行。
批量任务task:pauseAllGatewayContracts/task:unpauseAllGatewayContracts则经由GatewayConfig合约的pauseAllGatewayContracts()/unpauseAllGatewayContracts()函数间接操作全部可暂停合约,签名账户的选择逻辑与上述一致(暂停用PAUSER_PRIVATE_KEY,恢复用DEPLOYER_PRIVATE_KEY)。
所有任务还支持一个可选参数useInternalProxyAddress,为false(默认)时从.env中的GATEWAY_CONFIG_ADDRESS等变量读取代理地址,为true时改用/addresses目录下的内部代理地址。
底层合约如何校验密钥对应的身份
环境变量只是把私钥交给任务脚本,真正的权限校验发生在链上合约中。
Pausable 抽象合约:暂停/恢复的双重准入
Pausable.sol 继承 OpenZeppelin 的PausableUpgradeable,并定义了pause()与unpause():
pause():仅允许「注册在PauserSet中的暂停者」或GatewayConfig合约本身调用,否则 revertNotPauserOrGatewayConfig。unpause():仅允许「GatewayConfig的所有者」或GatewayConfig合约本身调用,否则 revertNotOwnerOrGatewayConfig。
这解释了为什么暂停用PAUSER_PRIVATE_KEY、恢复用DEPLOYER_PRIVATE_KEY:两者分别对应isPauser校验与owner校验。当GatewayConfig所有权转移给多签后,DEPLOYER_PRIVATE_KEY不再等于owner,恢复任务自然失效。
GatewayConfig:批量暂停/恢复的编排与幂等保护
GatewayConfig.sol 中:
pauseAllGatewayContracts()带onlyPauser修饰符(内部调用PAUSER_SET.isPauser(msg.sender)校验),会读取Decryption与InputVerification的paused()状态,仅暂停当前未暂停的合约;若两者都已暂停,则 revertAllGatewayContractsAlreadyPaused。unpauseAllGatewayContracts()带onlyOwner修饰符,仅恢复当前处于暂停状态的合约;若两者都未暂停,则 revertAllGatewayContractsAlreadyUnpaused。
从源码结构看,代码注释还指出:CiphertextCommits与GatewayConfig目前技术上可暂停但尚无可暂停函数,因此pauseAllGatewayContracts()不会暂停它们;KMSGeneration合约目前未被使用,也无需暂停。
暂停后哪些函数会被阻断
当合约处于暂停状态时,触发其"请求类"函数的交易会被 revert,而已发送请求的响应仍会被接受(进行中的共识可以继续达成),其余 view 函数也仍然可调用:
Decryption合约(见 Decryption.sol):publicDecryptionRequest、userDecryptionRequest、delegatedUserDecryptionRequest均带whenNotPaused修饰符,暂停时被阻断。InputVerification合约(见 InputVerification.sol):verifyProofRequest带whenNotPaused修饰符(该文件第 190 行附近),暂停时被阻断。
也就是说,暂停保护的是"新请求入口",而非"已在进行中的请求流程",这与 暂停机制文档 的描述完全一致。
配置与使用的完整步骤
本地测试环境
- 从 .env.example 复制生成
.env文件; - 确认
PAUSER_PRIVATE_KEY与PAUSER_ADDRESS_0(accounts[23])对应; - 确认
DEPLOYER_PRIVATE_KEY对应accounts[1]; - 运行
make get-accounts生成并查看已注资的 Hardhat 账户; - 在已部署网关合约的本地网络上执行暂停/恢复任务,例如:
npx hardhat task:pauseAllGatewayContracts npx hardhat task:unpauseAllGatewayContracts npx hardhat task:pauseDecryption npx hardhat task:unpauseDecryption npx hardhat task:pauseInputVerification npx hardhat task:unpauseInputVerification生产环境
- 每个运营商将
PAUSER_PRIVATE_KEY设置为自己的热钱包(暂停者)私钥; - 只要
GatewayConfig仍由部署者(或由部署者私钥控制)持有所有权,DEPLOYER_PRIVATE_KEY即可用于恢复; - 所有权一旦移交多签,恢复必须改走多签调用
GatewayConfig.unpause的治理流程,DEPLOYER_PRIVATE_KEY将不再具备恢复权限。
安全要点总结
- 暂停者预期是运营商控制的热钱包,私钥泄露风险由运营商自行管理;
PAUSER_PRIVATE_KEY与DEPLOYER_PRIVATE_KEY权限不对称:前者只能暂停,后者(作为所有者)既能恢复,也掌握GatewayConfig的全部管理职能;- 所有权移交多签是安全模型的一部分:此后即使持有部署者私钥也无法单独恢复合约,防止单点故障;
- 两个变量的 Solidity 类型均为
bytes32,与账户私钥的 32 字节格式一致,配置时必须带上0x前缀。
如需深入了解暂停的完整工作流、PauserSet的暂停者管理函数,或部署时其他环境变量的说明,可继续阅读 暂停机制文档、PauserSet 合约文档、部署环境变量文档 与 本地部署指南。
【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考