如何在 Midnight 编写 smart contracts
Source: Dev.to
心智模型:默认隐私
在写一行代码之前,需要改变思路。
在 Midnight:
- 来自用户的所有数据默认是私有的。
- 任何东西都不可能因“意外”而公开。
- 隐私是显式控制的,而不是隐式的。
这得益于 Compact——Midnight 的智能合约语言,以及使用 Zero‑Knowledge Proofs (zkSNARKs) 在不泄露数据的情况下验证交易。
什么是 Compact?
Compact 是一种声明式语言,专门用于构建 隐私优先 的应用。
当你在 Compact 中编写合约时:
- 定义业务逻辑。
- 定义哪些数据是公开的。
- 定义哪些数据保持私有。
编译器会生成:
- 用于你的 DApp 的 JavaScript / TypeScript API。
- 生成零知识证明所需的加密工件。
所有这些都在开发者本地环境中完成。
Compact 合约的基本组成
Midnight 中的每个合约都由相同的模块构成:
Ledger state(公共状态)
存储在链上并对所有人可见的数据。
export ledger value: Uint;
Witnesses(私有输入)
witness 表示来自用户或前端的数据。默认私有,Compact 不允许意外泄露。
witness getSecret(): Bytes;
Circuits(可验证逻辑)
circuits 定义合约可以执行的操作。只有标记为 export 的 circuits 才能被外部调用。
export circuit get(): Uint {
return value;
}
Constructor
在创建合约时执行一次。
constructor(sk: Bytes, v: Uint) {
value = v;
}
选择性披露:disclose()
Compact 最重要的规则之一是:
不能在未明确声明的情况下将私有数据公开。
如果直接在账本中使用 witness 或作为返回值,编译器会报错。
正确写法:
export ledger publicData: Bytes;
export circuit record(): [] {
publicData = disclose(getSecret());
}
错误写法(编译错误):
publicData = getSecret(); // ❌
这消除了其他生态系统中常见的一整类错误。
Opaque types:当 Compact 不应“查看”数据时
Compact 支持不透明类型,如 Opaque。这些类型:
- 可以存储或转移。
- 合约内部不能检查其内容。
- 在前端(TypeScript)可见,但在 Compact 中不可操作。
它们适用于:
- 消息
- 元数据
- 任意内容(例如公告板)
- 承诺与哈希
用于无泄露数据验证的密码学原语
为了在不泄露数据的前提下验证属性,Compact 提供了:
persistentCommit(value, random);
transientCommit(value);
这些函数是以下场景的关键:
- 私密投票
- 可验证身份
- 在不泄露凭证的情况下进行认证
Proof server 的角色
所有零知识魔法都在区块链之外完成。proof server:
- 在本地或受控基础设施上运行。
- 永不向网络暴露私有数据。
- 只返回有效的加密证明。
这使得区块链能够在 不知晓底层数据 的情况下验证事实。
在 Midnight 中如何思考合约
在 Midnight 编写合约时,建议自问:
- 这条数据真的需要公开吗?
- 网络需要验证什么,而不需要验证什么?
- 我能在不泄露数值的情况下证明这个条件吗?
- 谁在控制 proof server?
Compact 不仅提供工具,还强迫你仔细思考数据模型。
结论
在 Midnight 上编写智能合约不仅是学习一门新语言,更是采用一种全新的去中心化应用设计方式:
- 默认隐私
- 显式披露
- 数据、逻辑与证明的清晰分离
- 编译器层面的强化安全
如果你来自 Solidity、Plutus 等生态系统,Compact 起初可能会感觉不同。但一旦模型形成,你会发现很难回头。隐私不再是一个“特性”,而是语言本身的一部分。