跳到主要内容

最佳实践与反模式

机密合约开发速查表。发布任何敏感内容之前先扫一遍。

应当做

假设存储布局是公开的。 存储槽地址不加密——只有值加密。如果你的槽访问模式泄漏了结构信息,那份信息就泄漏了。对高敏感合约,考虑填充、伪写入或 oblivious 数据结构。

理解谁能解密事件日志。 事件内容用调用者的会话密钥加密。全局索引器无法跨用户解密它们。事件策略要提前设计——见机密性模型:事件日志的坑

在 Hardhat / Foundry / solc 配置里锁定 evmVersion: "paris" 更晚的 EVM 版本包含 OXN 当前不支持的 PUSH0。见 EVM 兼容性

集成测试里断言 tx.data 是加密的。 每笔重要交易之后断言 tx.data 以 CBOR 信封字节开头。这能在"忘记 wrap signer"这个 bug 进生产前抓住它。检查方式见加密调用 vs 明文调用

在真实 OXN 网络上测试,别在本地 Hardhat。 本地 EVM 模拟器不建模 TEE 行为、加密 calldata、签名查询。"跑通了 hardhat network"对你生产行为毫无证明力。

private 存储 + 显式 view 函数。 别对本该机密的存储用 public——它会生成一个明文无认证 getter,抹掉加密。通过 msg.sender 门控的显式 view 函数暴露数据。

显式设置 gas limit。 OXN 上每笔交易都要显式设置 gasLimit,客户端估算不是推荐路径。推荐默认值:普通状态改动 500k,部署 3-5M。

应当避免

别在事件里 emit 敏感数据(如果你需要全局索引器)。 事件只有调用者能解密。如果你必须让公开可观察,就 emit 一个不含敏感字段的明文伴随事件,或者用独立的公开中继合约。

别用 block.timestampblock.number 做随机数。 它们公开、可预测、可被验证人操纵。用 Sapphire.randomBytes 预编译——它从 TEE 认证的熵源取值。

别假设 gas 成本是机密的。 Gas 是公开硬件上的计量。如果你合约的执行成本依赖某个秘密的值(在加密状态上分支),gas 使用量就会泄漏这个值。可能的地方改成常数时间;见机密性陷阱

别因为"反正状态加密"就跳过访问控制。 加密隐藏值不让外部看,不阻止授权调用方读到全部。如果合约有管理员、用户、第三方,每类都需要独立的授权路径。见访问控制模式

别用 view 函数做授权判断的最终执行。 view 函数不消耗 gas、不持久化状态。require(msg.sender == owner) 放在 view 里做看什么的门控没问题,但别把它当作改状态操作的唯一执行门。

别以为"机密"能替代"审计"。 存在于以太坊的每一种智能合约安全 bug 也存在于 OXN——重入、溢出、未检查调用、预言机操纵。机密性是数据隐私特性,不是代码安全特性。上审计过的代码。

别对敏感字段用 indexed emit 事件。 Indexed 事件 topic 会被哈希进每个区块头里的 Bloom filter。即便 topic 加密,通过 eth_getLogs 过滤模式它的存在是可推断的。

情境:什么时候用明文调用

不是一切都要加密。合理的明文调用场景:

  • 读公开常量。 合约配置、管理员地址、代理指向。
  • 调用不存机密的目标合约。 调用公开预言机、明文中继、故意公开余额的 ERC-20。
  • 调试。 你需要看链上真实字节的场合,需要它们是明文的。
  • 与不知道 OXN 的工具互操作。 有些第三方工具无法构造加密信封。对公开接口的明文调用照样能用。

如果明文是有意的,在代码里注释。否则看起来像 bug。

情境:什么时候不该用 OXN

OXN 不总是对的工具。

  • 你的数据本就公开。 公开流动性池、预言机价格、公开 NFT 市场——用以太坊或 L2。
  • 你需要把状态转移发布到更大的链上。 那是 rollup,不是 OXN。
  • 你的威胁模型是有硬件攻击预算的国家级对手。 叠加 ZK 证明或你自己控制的链下 enclave。
  • 你的合约没机密,只有昂贵计算。 那你要的是扩展,不是隐私。

下一步