本文档描述了用于保持整个系统不断发展的各种机制。

说明

Ledger版本控制

ledgerVersion

存储在分块头中的此uint32描述了整个协议的版本号。 在这种情况下,协议被定义为“有线格式” - 即,存储在分块中的所有对象的序列化形式 - 及其行为。

每次协议更改时,此版本号都会递增。

与共识相结合

大多数时候,只需就哪个交易集需要应用于前一个分块达成共识。

但是,也可以就升级步骤达成共识。

一个这样的升级步骤是“在分块N之后将ledgerVersion更新为值X”。

如果节点不认为升级步骤有效,他们只需从他们的投票中删除升级步骤。

节点认为步骤无效,因为它们不理解它或者某些条件不满足。 在前面的示例中,可能是节点不支持X,或者分块编号尚未达到N.

在应用交易集之前应用升级步骤,以确保逻辑调度步骤与处理它的步骤相同。 否则,必须在分块关闭后应用这些步骤。

支持的版本

每个节点都有自己的方式来跟踪它支持的版本 - 例如,“最小版本”,“最大版本” - 但它也可以包括“黑名单版本”之类的内容。协议中不会跟踪支持的版本。

请注意,minProtocolVersion与实例理解的版本不同:通常,实现了解版本n ... maxProtocolVersion,其中n <= minProtocolVersion。 这样做的原因是节点必须能够从历史记录(直到版本'n')重放交易,但是可能存在一些我们不希望可用于新交易的问题/漏洞。

Ledger对象版本控制

可能随时间演变的数据结构包含以下扩展点:

union switch(int v)
{
case 0:
    void;
} ext;

在这种情况下,版本“v”指的是对象的版本并允许添加新的武器。

该方案提供了几个好处:

  • 只有更新协议定义文件,实现才能在不更改代码的情况下实现线路兼容。
  • 即使没有更新协议定义文件,只要它们不遇到更新的格式,旧的实现就会继续运行。
  • 它促进了对象版本之间的代码共享。

请注意,虽然此方案促进了使用这些对象的组件的代码共享,但是对于POCChain本身不一定提升代码共享,因为必须为所有版本保留行为:为了从任意时间点重建分块链,行为 必须100%兼容。

操作版本控制

操作作为整体进行版本化:如果需要添加或更改新参数,则通过添加新操作来实现版本控制。 这会在客户端中导致一些逻辑重复,但避免引入潜在的错误。 例如,仅签署某些类型的交易的代码必须完全了解它的签名。

信封版本控制

用于允许信封可扩展性的模式(签名内容):

union TransactionEnvelope switch (int v)
{
case 0:
    struct
    {
        Transaction tx;
        DecoratedSignature signatures<20>;
    } v0;
};

此模式允许在需要时修改信封,并确保客户端不会盲目地使用无法验证的内容。

升级没有扩展点的对象

必须克隆对象的模式,并且必须更新其父对象以使用新的对象类型。 这里的假设是没有未版本化的“root”对象。

支持实现生命周期考虑

为了使代码库保持可维护状态,实现可能无法保留从创建中回放的能力。 相反,他们可能会选择支持有限的范围 - 例如,只保留重播前3个月交易的能力(假设网络的minProtocolVersion比这更新)。

这不会改变节点(重新)加入或参与网络的能力; 它只影响节点进行历史验证的能力。

叠加版本控制

Overlay遵循类似的版本控制模式:它具有min-maxOverlayVersion。

在涉及弃用计划时,覆盖层的版本控制策略更具攻击性;涉及的节点集仅限于直接连接到实例的节点。

考虑到这一点,结构遵循此层的“克隆”模型:如果需要修改消息,则通过使用新类型标识符克隆旧消息类型来定义新消息。

知道无论如何都会删除旧的实现,克隆模型可以重构大部分代码,避免了维护旧版本的麻烦。

在此层,只要它保持兼容,就可以修改旧版本的行为。

实现可以决定共享底层代码 - 例如,通过在内部将遗留消息转换为新格式。

当对等体彼此连接时交换的“HELLO”消息包含实例支持的最小和最大版本。如果另一个接口不兼容,则可以决定立即断开连接。