变更记录
- 2021年9月22日:初始草案
状态
提议中摘要
本 ADR 描述了一种关于 Cosmos SDK 模块如何使用、交互以及存储各自参数的替代方案。背景
目前,在 Cosmos SDK 中,需要使用参数的模块会使用x/params 模块。x/params 的工作方式是由模块定义参数,通常通过一个简单的 Params 结构体完成,并通过一个归属于相应注册模块的唯一 Subspace 将该结构体注册到 x/params 模块中。注册模块随后即可独占访问其对应的 Subspace。模块可以通过这个 Subspace 获取和设置其 Params 结构体。
此外,Cosmos SDK 的 x/gov 模块原生支持通过链上参数变更来修改参数,具体方式是使用 ParamChangeProposal 治理提案类型,由利益相关方对建议的参数变更进行投票。
使用 x/params 模块管理各个模块参数存在多种权衡。也就是说,参数管理在某种程度上几乎是“免费”的,因为开发者只需要定义 Params 结构体、Subspace 以及各种辅助函数,例如 Params 类型上的 ParamSetPairs。不过,这种方式也有一些明显缺点。这些缺点包括:参数通过 JSON 序列化后存储到状态中,而这会非常慢。此外,通过 ParamChangeProposal 治理提案进行参数变更时,无法读取或写入状态。换句话说,目前在尝试修改参数时,应用程序无法执行任何状态转换。
决策
我们将在 #9810 中x/gov 与 x/authz 工作对齐的基础上继续推进。具体来说,模块开发者将创建一个或多个唯一的参数数据结构,并将其序列化存储到状态中。参数数据结构必须实现 sdk.Msg 接口,并提供相应的 Protobuf Msg service 方法,用于校验和更新参数以及执行所有必要变更。x/gov 模块将通过 #9810 中完成的工作分发参数消息,这些消息将由 Protobuf Msg service 处理。
需要注意的是,参数以及对应 sdk.Msg 消息应如何组织,由开发者自行决定。以下以当前 x/auth 中使用 x/params 模块进行参数管理的参数定义为例:
Params 中的每个字段分别创建唯一的数据结构,也可以像上面 x/auth 的示例那样,只创建一个 Params 结构体。
在前一种即 x/params 风格的做法中,需要为每一个字段创建一个 sdk.Msg 以及对应的处理器。如果参数字段很多,这会变得很繁琐。在后一种做法中,只有一个数据结构,因此也只需要一个消息处理器;但相应地,该消息处理器可能需要更复杂一些,因为它可能需要区分哪些参数被修改了,哪些参数未被触及。
参数变更提案通过 x/gov 模块发起。执行则通过对根 x/gov 模块账户的 x/authz 授权完成。
继续以 x/auth 为例,下面给出一个更完整的示例:
Service 查询,例如:
影响
采用这种模块参数方法后,我们将获得让模块参数变更具备状态性并可扩展到几乎所有应用场景的能力。我们将能够发出事件(并通过 event hooks 中提出的工作触发注册到这些事件上的钩子)、调用其他 Msg service 方法,或执行迁移。 此外,在从状态读取参数以及向状态写入参数时,性能也将显著提升,尤其是在某一组特定参数被持续频繁读取的情况下。 不过,这种方法要求开发者实现更多类型和 Msg service 方法;如果参数很多,这可能会带来负担。此外,开发者还需要自行实现模块参数的持久化逻辑。 不过,这应当是比较简单的。向后兼容性
这种新的模块参数处理方法天然不兼容现有的x/params 模块。不过,x/params 仍会保留在 Cosmos SDK 中,并被标记为已弃用;除潜在的 bug 修复外,不会再增加新的功能。需要注意的是,x/params 模块可能会在未来的版本中被彻底移除。
正面影响
- 模块参数的序列化效率更高
- 模块能够对参数变更作出响应并执行额外操作。
- 可以发出特殊事件,从而触发钩子。
负面影响
- 对模块开发者来说,模块参数的处理会稍微更繁琐一些:
- 模块现在需要自行负责参数状态的持久化和读取
- 模块现在需要为每种唯一的参数数据结构提供唯一的消息处理器,以处理对应的参数变更。
中性影响
- 需要先审查并合并 #9810。
参考资料
Changelog
- Sep 22, 2021: Initial Draft
Status
ProposedAbstract
This ADR describes an alternative approach to how Cosmos SDK modules use, interact, and store their respective parameters.Context
Currently, in the Cosmos SDK, modules that require the use of parameters use thex/params module. The x/params works by having modules define parameters,
typically via a simple Params structure, and registering that structure in
the x/params module via a unique Subspace that belongs to the respective
registering module. The registering module then has unique access to its respective
Subspace. Through this Subspace, the module can get and set its Params
structure.
In addition, the Cosmos SDK’s x/gov module has direct support for changing
parameters on-chain via a ParamChangeProposal governance proposal type, where
stakeholders can vote on suggested parameter changes.
There are various tradeoffs to using the x/params module to manage individual
module parameters. Namely, managing parameters essentially comes for “free” in
that developers only need to define the Params struct, the Subspace, and the
various auxiliary functions, e.g. ParamSetPairs, on the Params type. However,
there are some notable drawbacks. These drawbacks include the fact that parameters
are serialized in state via JSON which is extremely slow. In addition, parameter
changes via ParamChangeProposal governance proposals have no way of reading from
or writing to state. In other words, it is currently not possible to have any
state transitions in the application during an attempt to change param(s).
Decision
We will build off of the alignment ofx/gov and x/authz work per
#9810. Namely, module developers
will create one or more unique parameter data structures that must be serialized
to state. The Param data structures must implement sdk.Msg interface with respective
Protobuf Msg service method which will validate and update the parameters with all
necessary changes. The x/gov module via the work done in
#9810, will dispatch Param
messages, which will be handled by Protobuf Msg services.
Note, it is up to developers to decide how to structure their parameters and
the respective sdk.Msg messages. Consider the parameters currently defined in
x/auth using the x/params module for parameter management:
Params or they can create a single Params structure as outlined above in the
case of x/auth.
In the former, x/params, approach, a sdk.Msg would need to be created for every single
field along with a handler. This can become burdensome if there are a lot of
parameter fields. In the latter case, there is only a single data structure and
thus only a single message handler, however, the message handler might have to be
more sophisticated in that it might need to understand what parameters are being
changed vs what parameters are untouched.
Params change proposals are made using the x/gov module. Execution is done through
x/authz authorization to the root x/gov module’s account.
Continuing to use x/auth, we demonstrate a more complete example:
Service query should also be provided, for example:
Consequences
As a result of implementing the module parameter methodology, we gain the ability for module parameter changes to be stateful and extensible to fit nearly every application’s use case. We will be able to emit events (and trigger hooks registered to that events using the work proposed in event hooks), call other Msg service methods or perform migration. In addition, there will be significant gains in performance when it comes to reading and writing parameters from and to state, especially if a specific set of parameters are read on a consistent basis. However, this methodology will require developers to implement more types and Msg service methods which can become burdensome if many parameters exist. In addition, developers are required to implement persistence logic for module parameters. However, this should be trivial.Backwards Compatibility
The new method for working with module parameters is naturally not backwards compatible with the existingx/params module. However, the x/params will
remain in the Cosmos SDK and will be marked as deprecated with no additional
functionality being added apart from potential bug fixes. Note, the x/params
module may be removed entirely in a future release.
Positive
- Module parameters are serialized more efficiently
- Modules are able to react on parameters changes and perform additional actions.
- Special events can be emitted, allowing hooks to be triggered.
Negative
- Module parameters becomes slightly more burdensome for module developers:
- Modules are now responsible for persisting and retrieving parameter state
- Modules are now required to have unique message handlers to handle parameter changes per unique parameter data structure.
Neutral
- Requires #9810 to be reviewed and merged.