最佳实践与反模式
机密合约开发速查表。发布任何敏感内容之前先扫一遍。
应当做
假设存储布局是公开的。 存储槽地址不加密——只有值加密。如果你的槽访问模式泄漏了结构信息,那份信息就泄漏了。对高敏感合约,考虑填充、伪写入或 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.timestamp 或 block.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 过滤模式它的存在是可推断的。