工作原理
该模型有两条规则:- 只有在持有对另一个对象的引用时,一个对象才能向该对象发送消息。
- 一个对象只能通过接收消息的方式,获得对另一个对象的引用。
指针与值
只传递模块实际需要的内容。如果你传递的是指针,就授予了写权限;如果你传递的是值,就授予了读权限。 下面这段代码违反了这一原则:将指针传给外部模块,会让它能够修改该账户:Keeper 接口
在 SDK 模块中,应用 ocap 最常见的位置是 keeper 边界。与其接收来自其他模块的具体 keeper 类型,不如定义一个精简接口,只包含你的模块实际会调用的方法。 例如,x/distribution 需要查询余额并发送代币,但它并不需要完整的 bank keeper。它定义了自己的接口:
types/expected_keepers.go 中。这样做有两方面好处:一是接口明确记录了你的模块所需的跨模块访问能力;二是这种依赖在测试中很容易 mock。
Store 隔离
模块不会直接获得全局 multistore 的访问权限。相反,每个模块都会获得一个作用域限定在自身前缀下的store.KVStoreService,因此它只能在该命名空间内读写。
Authority
某些操作,例如更新参数、暂停模块、触发紧急操作,只应允许治理或其他受信任账户调用。SDK 通过在 keeper 中存储一个显式的authority 字符串来处理这一点。
authority 地址会在 app.go 中的连接阶段设置,且运行时不能更改。这就是将 ocap 应用于治理:特权能力本质上是一种引用,只有持有该引用的一方才能行使它。
可参考 simapp/app.go,了解在完整应用中 keeper 依赖和 authority 是如何连接的。
相关背景可参阅 Wikipedia 上关于 object-capability model 的文章。
The Cosmos SDK is built around the object-capability model (ocap) — a security model designed for systems that compose untrusted components. The threat model is explicit: a thriving ecosystem of Cosmos SDK modules will eventually include faulty or malicious ones. Ocap limits the damage any single module can do.
How it works
The model has two rules:- An object can send a message to another object only if it holds a reference to it.
- An object can obtain a reference to another object only by receiving it through a message.
Pointer vs. value
Only pass what a module needs. If you pass a pointer, you grant write access. If you pass a value, you grant read access. This code violates the principle — passing a pointer to an external module grants it the ability to mutate the account:Keeper interfaces
The most common place to apply ocap in SDK modules is at keeper boundaries. Instead of accepting a concrete keeper type from another module, define a narrow interface containing only the methods your module actually calls. For example,x/distribution needs to query balances and send coins, but it does not need the full bank keeper. It defines its own interface:
types/expected_keepers.go. The benefit is twofold: the interface documents exactly what cross-module access your module requires, and it makes the dependency easy to mock in tests.
Store isolation
Modules do not receive direct access to the global multistore. Instead, each module gets astore.KVStoreService scoped to its own prefix — it can only read and write within that namespace.
Authority
Some operations — updating parameters, pausing a module, triggering emergency actions — should only be callable by governance or another trusted account. The SDK handles this with an explicitauthority string stored in the keeper.
app.go and cannot be changed at runtime. This is ocap applied to governance: privileged capability is a reference, and only the holder of that reference can exercise it.
See simapp/app.go for how keeper dependencies and authorities are wired in a complete application.
For background, see the Wikipedia article on object-capability model.