变更日志

  • 2019年11月26日:第一版开始
  • 2019年12月2日:第一版最终草案

背景

为了让 Cosmos SDK 实现 IBC 规范,Cosmos SDK 内的模块必须能够检查最近的共识状态(验证者集合和承诺根),因为在握手过程中需要校验这些值在其他链上的证明。

决策

应用程序必须在持久化存储中保存最近的 n 个区块头。最初,这个存储可以是当前的 Merklised 存储。之后也可以使用非 Merklised 存储,因为不需要证明。 应用程序必须在处理 abci.RequestBeginBlock 时立即存储新区块头,以保存这些信息:
func BeginBlock(ctx sdk.Context, keeper HistoricalHeaderKeeper, req abci.RequestBeginBlock)

abci.ResponseBeginBlock {
    info := HistoricalInfo{
    Header: ctx.BlockHeader(),
    ValSet: keeper.StakingKeeper.GetAllValidators(ctx), // note that this must be stored in a canonical order
}

keeper.SetHistoricalInfo(ctx, ctx.BlockHeight(), info)
    n := keeper.GetParamRecentHeadersToStore()

keeper.PruneHistoricalInfo(ctx, ctx.BlockHeight() - n)
  // continue handling request
}
或者,应用程序也可以只存储验证者集合的哈希。 应用程序必须通过 Keeper 的 GetHistoricalInfo 函数,向 Cosmos SDK 模块提供对过去这 n 个已提交区块头的查询能力。这个能力可以实现为一个新模块,也可以集成到现有模块中(很可能是 x/staking 或 x/ibc)。 n 可以配置为参数存储中的一个参数,这样就可以通过 ParameterChangeProposal 进行修改。不过,如果增大 n,已存储的信息需要经过若干个区块后才能补齐。

状态

提议中。

影响

实现此 ADR 需要对 Cosmos SDK 进行修改,但不需要对 Tendermint 进行修改。

正面影响

  • Cosmos SDK 中任意位置的模块都可以轻松获取最近历史高度的区块头和状态根。
  • 无需对 Tendermint 发起 RPC 调用。
  • 无需修改 ABCI。

负面影响

  • 在 Tendermint 和应用程序中重复存储了 n 份区块头数据(会增加磁盘使用量)。从长期来看,可能更适合采用类似这里的方法。

中性影响

(暂无已知)

参考资料


Changelog

  • 26 November 2019: Start of first version
  • 2 December 2019: Final draft of first version

Context

In order for the Cosmos SDK to implement the IBC specification, modules within the Cosmos SDK must have the ability to introspect recent consensus states (validator sets & commitment roots) as proofs of these values on other chains must be checked during the handshakes.

Decision

The application MUST store the most recent n headers in a persistent store. At first, this store MAY be the current Merklised store. A non-Merklised store MAY be used later as no proofs are necessary. The application MUST store this information by storing new headers immediately when handling abci.RequestBeginBlock:
func BeginBlock(ctx sdk.Context, keeper HistoricalHeaderKeeper, req abci.RequestBeginBlock)

abci.ResponseBeginBlock {
    info := HistoricalInfo{
    Header: ctx.BlockHeader(),
    ValSet: keeper.StakingKeeper.GetAllValidators(ctx), // note that this must be stored in a canonical order
}

keeper.SetHistoricalInfo(ctx, ctx.BlockHeight(), info)
    n := keeper.GetParamRecentHeadersToStore()

keeper.PruneHistoricalInfo(ctx, ctx.BlockHeight() - n)
  // continue handling request
}
Alternatively, the application MAY store only the hash of the validator set. The application MUST make these past n committed headers available for querying by Cosmos SDK modules through the Keeper’s GetHistoricalInfo function. This MAY be implemented in a new module, or it MAY also be integrated into an existing one (likely x/staking or x/ibc). n MAY be configured as a parameter store parameter, in which case it could be changed by ParameterChangeProposals, although it will take some blocks for the stored information to catch up if n is increased.

Status

Proposed.

Consequences

Implementation of this ADR will require changes to the Cosmos SDK. It will not require changes to Tendermint.

Positive

  • Easy retrieval of headers & state roots for recent past heights by modules anywhere in the Cosmos SDK.
  • No RPC calls to Tendermint required.
  • No ABCI alterations required.

Negative

  • Duplicates n headers data in Tendermint & the application (additional disk usage) - in the long term, an approach such as this might be preferable.

Neutral

(none known)

References