完整文档页面(中文翻译)。文末附有来源说明。

阅读英文版

overviewreferencepruning

修剪(Pruning)

Canton 数据修剪与历史保留策略参考。

Canton 修剪的工作原理:保留、安全修剪标记以及参与者和同步器之间的协调。

当同步器编排命令的执行时,定序器、中介器和参与者会保留它们处理的数据/更改的记录:

  • 对于参与者来说,存储的数据代表激活和停用的合约,及其相关的交易和事件
  • 对于排序者来说,存储的数据代表他们处理的消息以及参与者订阅状态的变化
  • 对于调解员来说,存储的数据代表他们根据参与者发送给调解员的确认响应向参与者发送的判决
  • 此外,所有节点都存储它们所连接的同步器的当前和过去的拓扑数据

由于这些节点无限期地连续运行,因此它们积累的存储数据(或者换句话说,账本的历史记录)不断增长。

在节点上永久积累和存储历史记录是有问题的,原因如下:

  • 首先,节点的存储量是有限的,如果存储的数据不断增长,它们最终会耗尽
  • 其次,有关隐私的法规可能要求根据要求删除个人身份信息 (PII)。例如,为了遵守欧洲的《通用数据保护条例》(GDPR),Canton 运营商必须声明合理的保留期,并确保随后删除数据。另一个例子,在健康信息方面,《健康保险流通与责任法案》(HIPAA) 旨在保护敏感的患者数据,决定数据应保留多长时间以及何时应删除。

修剪解决了围绕历史积累和存储的这些问题。首先,节点可以忘记历史的前缀,而不是存储整个历史,而是存储总结历史的状态快照。也就是说,修剪是指从参与者、排序器和调解器中删除旧的、过时的或不需要的数据。这意味着操作所需的数据不会被删除,例如,修剪永远不会删除活动的(即非存档的)Daml 合约。其次,参与者、排序者或调解者的每个运营商都可以根据自己及其客户的需求以及他们所运营的监管框架的要求来设置和定制修剪计划。节点运营商决定何时修剪以及保留哪些数据,但须遵守 Canton 实施所施加的限制。有关如何配置修剪的详细信息,请参阅参与者修剪的操作指南以及排序器和中介修剪的操作指南。

修剪意味着节点可以忘记历史的前缀,而是存储总结历史的状态快照。

以下部分解释历史记录和状态快照之间的差异,然后介绍修剪保护措施以确保节点不会删除所需的数据,最后解释节点如何在修剪历史记录之前就状态快照达成一致。

历史与状态快照

历史记录表示到特定时间点的所有更改的列表,而状态快照(或简洁快照)表示在特定时间点所有更改的摘要。考虑历史与快照的一个类比是想象一个操作员想要在时间 t 引导工作系统中的节点。例如,操作员想要添加新的参与者节点并在其上托管一些参与者,或者可能想要从备份中恢复现有的参与者。快照表示参与者在加入时需要在系统中运行的所有数据,其中包括但不限于在时间 t 时将各方作为利益相关者托管在参与者上的活动合约。相反,历史代表了从系统启动到时间 t 为止改变利益相关者合约的所有事件,例如创建、归档、重新分配。操作员可以简单地从时间 t 的快照进行引导。或者,如果由于某种原因不可用,操作员可以从先前时间 t-delta 的快照引导,然后重放时间戳 t-delta 和 t 之间的历史记录。下图以活跃合约为例展示了历史记录和快照之间的对比。

<图片src =“https://mintcdn.com/cantonfoundation/zmlOjLpKuDjnaObr/images/docs_website/pruning-history _v_snapshot.svg?fit=max&auto=format&n=zmlOjLpKuDjnaObr&q=85&s=e7f58996f0cb0736e79d040ccd3882fb" className="align-center" style={{width: "80.0%"}} alt="image" width="1219" height="476" data-path="images/docs_website/pruning-history_v_snapshot.svg" /> 参与者将其一些历史数据保留在长期存储中,称为参与者查询存储 (PQS)\_。 PQS 是一家独立于 Canton 内部存储的商店。 PQS 存储历史的精炼版本,其作用是回答有关过去的查询,例如出于监管目的。 在时间 t 修剪节点会删除该节点上存储到时间 t 的历史记录,但保留该节点在时间 t 的快照。节点的快照取决于节点的类型:参与者、同步者、中介者。一旦节点被修剪到时间 t,它将无法服务 t 之前的事件。

为了清楚起见,有必要区分修剪时间戳和应用程序处理的最新时间戳。考虑一个参与者节点,其账本末端位于偏移量 off_end 处,并且其操作员想要将该参与者节点修剪到偏移量 off_prune 处。 off_prune 定义快照的时间 t。假设t_end对应于off_end。从t时刻的快照来看,off_prune和off_end之间的变化发生在“未来”,t时刻的快照无法概括它们;而从应用程序的角度来看,一直处理到 off_end,off_prune 和 off_end 之间的更改已经成为历史记录的一部分。显然,在时间 t (或偏移量 off_prune)进行修剪不会删除 off_prune 之后的更改,即使这些更改不是 t 时快照的一部分。

参与者节点在 t 的快照包含以下内容:

  • 在时间 t 时,利益相关者托管在该参与者上的一组活跃合约。该集合对于参与者节点正确参与 Canton 的交易处理至关重要,例如,参与者通过拒绝此类交易来保护双重支出。

  • 时间 t 的飞行中重新分配。作为合同的重新分配参与者的参与者必须在重新分配正在进行时(即取消分配或分配命令未完成时)保留重新分配数据。否则,参与者将无法正确批准或拒绝重新分配。有关重新分配的更多详细信息,请参阅重新分配部分。目前,参与者不会删除他们的重新分配数据,但是,这是计划在未来进行的。

  • 参与者的私钥。目前,参与者需要所有密钥材料,而不仅仅是在时间 t 有效的密钥。参与者使用这些密钥通过签署这些消息来验证其发送到其他节点的消息。

  • t 之前的所有过去的拓扑快照。过去的拓扑快照是必要的,因为参与者可能需要提供它们以验证未来的请求,例如验证取消分配请求中的目标时间戳。 t 时的拓扑快照是必要的,因为它通知参与者存在哪些节点(中介者、定序器、参与者)、每个同步器对参与者施加哪些限制(例如,参与者可以托管的最大参与方数量)、哪些参与方托管在哪些参与者上等。因此,参与 Canton 交易协议的所有节点都知道在时间 t 的交易中涉及哪些参与者、他们使用哪些密钥等。

  • 在某些情况下命令重复数据删除。每个参与者都会累积通过该参与者提交的命令,并将其用作重复数据删除信息,以免多次提交事务。参与者在 t_end 结束的时间窗口内保留此重复数据删除信息。如果配置的以 t_end 结束的重复数据删除窗口足够大以包含 t,则 t 处的快照包含以 t 结束、持续时间为 deduplication window - (t_end - t) 的窗口的重复数据删除数据。否则,t 处的快照不包含任何重复数据删除数据。

中介者的快照包括:* t 时刻的拓扑状态。拓扑信息使中介者能够知道哪些参与者参与了交易,因此应该发送确认响应或拒绝交易。

  • 某些情况下的重复数据删除信息(类似于参与者命令的重复数据删除数据)。重复数据删除信息包含调解器在最近时间窗口内看到的事务,这是必要的,以便调解器可以防止同一事务的多次执行。
  • 中介者的私钥在时间 t 有效,用于身份验证目的。

定序器的快照包括:

  • t 之前的所有过去拓扑快照。定序器需要过去的拓扑快照,因为参与者可能会在其提交请求上指定拓扑时间戳,这会影响定序器解析组地址的方式。此外,定序器应该充当所有拓扑事务的基本事实,因为参与者从定序器下载他们的加入拓扑数据,这需要包括所有过去的拓扑事务,正如我们上面所解释的。定序器需要时间 t 的拓扑信息来了解时间 t 的同步器成员(参与者、定序器、中介器)。

  • 在同步器上注册的每个成员的先前时间戳。定序器提供全局全序多播,其中事件具有唯一的时间戳,并且成员从这些时间戳导出全局排序。通过将同一成员的前一个事件的时间戳与每个事件一起存储,定序器使每个成员能够检测该成员的事件流中的间隙。先前的时间戳对于参与者审核至关重要,因为它们使参与者能够向审核者证明参与者透露了从定序器收到的完整消息序列。

  • 使用 BFT Orderer 时与排序层相关的数据项。 BFT 排序者以一系列有序区块的形式组织交易,它需要保留这些区块,以便赶上并加入其他 BFT 节点,并将区块重新传输到错过最近消息的节点,以使它们摆脱困境。 (注意:对于 BFT 排序器以外的排序层,例如基于外部驱动程序的排序层,剪枝是单独处理的。)

  • 定序器的私钥在时间 t 有效,用于身份验证目的。

修剪保障措施

剪枝需要确保我们不会删除节点运行仍然需要的数据。决定删除哪些数据时需要考虑三个因素:用于操作连续性的快照、崩溃恢复数据和不可否认性保证。

用于操作连续性的快照

为了正常运行,每个节点都需要在时间 t 获得其快照,如上所述。因此:

参与者

  • 切勿删除活动的合约。
  • 永远不会删除重复数据删除窗口中最近观察到的事务,该窗口具有可配置的 length ledger-api.max-deduplication-duration。这意味着修剪的最小保留期至少是配置的最大重复数据删除期。
  • 切勿删除其正在进行的重新分配。事实上,参与者尚未修剪重新分配数据,尽管这是计划在未来进行的。

调解人

  • 绝不删除重复数据删除窗口中的数据,该窗口的长度是可配置的。

定序器:* 绝不删除数据,例如会员之前的时间戳,除非会员确认不再需要它。然而,作为对无响应成员的保护措施,定序器操作员可以指定数据保留窗口并进行修剪,而无需成员的确认。如果成员确实需要较旧的数据,他们将无法恢复它。有关详细信息,请参阅全局同步器 文档 和定序器修剪的操作指南。

  • 在指定时间的保留期内,绝不删除排序层数据(使用 BFT Orderer 时)。对于重传,当使用 BFT Orderer 时,排序器需要将排序层数据保留几个 epoch。为了帮助其他定序器赶上,他们需要在网络中至少一个节点仍需要帮助赶上时保留数据。但是,作为对无响应节点的保护措施,一旦数据保留窗口(默认为 30 天)过去,定序器操作员就会进行修剪。如果节点确实需要旧数据,它们需要离开网络并加入新数据。此外,如果整个系统停机的时间长于修剪保留期,我们不希望排序器在恢复时修剪所有内容。为了防止这种情况,操作员还可以指定要保留的最小块量。

一般

  • 节点尚未实现拓扑状态的修剪。虽然对于拓扑变化不频繁的系统来说,拓扑状态不会增长得太快,但Canton不修剪拓扑状态是系统的一个限制。拓扑修剪计划作为未来的工作。

崩溃恢复数据

节点不会删除与崩溃恢复相关的数据。精确的数据取决于参与者/中介者/排序器处理管道。

不可否认保证

参与者永远不会修剪早于时间 t 的历史记录,除非它有不可否认的证据证明与其他参与者在时间 t 的共享活跃合约集上达成一致。参与者可以在与其他参与者发生法律纠纷时使用这样的证据。在此意义上,参与者交换 ACS(活跃合约集)承诺,这是他们在特定时间点共享的活跃合约不可否认的总结。 ACS 承诺在下面的不可否认性部分中详细描述。

仅当参与者在时间 t 收到来自每个对方参与者的匹配的成对承诺消息时,才会在时间 t 修剪其历史记录。参与者还修剪修剪时间戳之前的时间戳的所有承诺。

手动修剪

还有一些数据项需要操作员手动管理,而不是通过修剪计划来管理。

  • 参与者节点运营商手动管理其 DAR(Daml 存档存储库)和包存储的修剪,其中包含参与者审查的合约。在具有长期运行参与者的 CI/CD 模型中,这些商店可以变得相当大。操作员需要决定何时不再需要这些数据,并通过控制台命令手动修剪这些存储。
  • 节点运营商手动管理加密材料的修剪,特别是私钥。操作员可以通过控制台命令手动删除密钥。
  • 节点操作员手动管理修剪配置数据,例如定序器连接、域别名、静态域参数等。但是,配置数据通常应该很小。

不可否认性

分叉表示网络中两个或多个参与节点对其共享状态的看法存在分歧的情况。分叉可能由于配置错误而发生,例如,通过修复服务、错误或恶意行为更改合约存储时。

为了保护每个参与节点的操作,Canton 协议包含一个分叉检测机制,通过确保共享合约的任何两个参与节点就这些合约的状态达成一致,原因有两个。首先,当参与者节点就其共享状态达成一致并且是诚实的时,它们在批准或拒绝交易时应该表现相同。例如,如果Alice和银行约定Alice在银行有一张IOU,那么Alice就可以使用该IOU进行支付。其次,就其共享状态达成一致的参与者节点可以修剪历史记录:只要状态匹配,参与者节点如何到达某个状态并不那么重要。然而,从法律角度来看,如果对方当事人后来可以提出相反的主张,那么仅仅达成一致是不够的。因此,参与节点可能需要一份协议证明。关于某些合同是否有效的同意或分歧的证据可能需要提交法庭。因此,我们需要对第三方有效的协议证明,即不可否认性

承诺使参与者节点能够验证其共享状态的协议,以便它们可以修剪历史记录。

重要的是,不活跃或恶意的参与者不能仅仅通过不发送承诺来阻止其对方参与者进行修剪。 Canton 通过使参与者能够配置不等待特定相对参与者的承诺来确保这一点,但代价是放弃与这些特定相对参与者的不可否认性。

参与者节点通过检查它们是否同意其共享合约状态来检测分叉。共享活跃合约的任何两个参与节点都会定期交换所谓的ACS(活跃合约集)承诺。承诺是参与者节点在某个时间点与某个相对参与者的活动合约的加密摘要。出于不可否认的目的,每个参与节点签署其承诺:具有匹配承诺的两个参与节点不能否认具有相同的共享 ACS 状态。对于两个参与者节点所连接的每个同步器以及它们共享活动合约的每个同步器来说,承诺生成和交换是一个独立的过程。两个参与者节点之间的匹配承诺证明它们就共享状态达成一致。

没有共享活动合约的两个参与节点不会交换承诺。

请注意,没有分叉并不意味着参与节点的共享交易历史是相同的,而是意味着它们当前的共享状态(即共享的活动合约)是相同的。要求就当前状态而不是历史达成一致的理由是,有效合约对于托管方的业务逻辑至关重要。只要参与节点就其共享状态达成一致,那么它们如何到达该状态就显得次要了。

接下来,我们详细描述承诺生成和交换过程,参与节点操作者如何检查和解决分叉原因,以及我们如何优化性能。

承诺交换

连接到同步器的成对参与者节点交换共享活动(先前激活,尚未停用)合约的承诺。如果每个参与者节点在合约处于活动状态的同步器上托管合约的某些利益相关者(不一定是同一利益相关者),则两个或多个参与者节点共享合约。每个参与者节点根据承诺时间戳处的拓扑,定期计算并向其所知的每个对方参与者节点发送承诺。参与节点通过同步器的定序器交换承诺。如果参与者节点的本地计算的承诺与接收到的承诺匹配,则参与者节点知道它同意对方参与者。两个参与节点都存储收到的签名承诺,稍后可以将其用作不可否认的加密证明。

参与节点交换承诺的频率是同步器参数,会影响性能和保证之间的权衡。较小的周期可以实现及时的分叉检测,但代价是参与节点上有更多的计算开销以及同步器上有更多的带宽开销。同步器操作员可以将动态同步器参数中的周期长度调整为持续时间(称为协调间隔)。

可以在运行的同步器上调整协调间隔。周期长度的更改立即生效。

承诺的格式为了达成有意义的协议,参与节点应该为其在同一时间点获取的共享状态生成承诺。每个参与者节点的 ACS 状态只能随着参与者节点从定序器接收到的事件而演变。因此,我们也将排序器时间用于承诺期是有意义的。参与节点从定序器接收多种事件类型,例如拓扑更改、ACS 更改等,这些事件类型带有定序器时间的时间戳。所有这些事件都提高了参与者节点对定序器时间的了解,并在时间跨越周期边界时触发承诺生成。参与者节点在承诺中捕获那些时间戳低于或等于承诺周期结束且在周期结束之前未停用的 ACS 合约激活。

参与节点观察者的定序器时间进步称为 **ticks**,据说会 *tick* ACS 承诺处理器。

在某些情况下,诚实的参与者节点可能不会在所有周期结束时发出承诺。协调间隔仅设置参与者节点计算和交换的承诺数量的上限,但要发布承诺,参与者节点需要看到一个勾号。一些参与者节点可能会主持许多方并由于相应的许多合约和拓扑事件而观察到蜱虫,而其他参与者节点可能不会。例如,考虑 1 分钟的时间段,参与者节点观察时间戳 10:20:03(并发出 10:20 的承诺),下一个观察时间戳为 10:28:50。当观察时间戳 10:28:50 时,参与节点可以对时间戳 10:21、10:22 等、10:28 发出承诺,但是,这是浪费的,因为它们将具有相同的内容。事实上,如果 ACS 在 10:21 到 10:28 之间发生变化,参与节点就会看到 ACS 提前时间发生变化,并且会发出更细粒度的承诺。因此,除了周期结束之外,每个承诺还包含一个周期开始,并表示该间隔涵盖的所有周期结束时的状态。接收到承诺的参与节点可以使用它来将其与间隔内任何周期结束时自己的状态进行比较。

每个承诺都包含总结 ACS 状态的加密哈希,以及有关期间和发送者的元数据。

尽管一些参与者节点可能不会在所有周期结束时发出承诺,但诚实、运作良好的参与者节点不会互相阻止修剪。假设参与者节点 A 和 B 共享活跃合约,并且 A 比 B 看到更多的蜱虫。这种情况可能会发生,例如,因为共享合约上没有太多活动,而参与者节点 A 托管了更多参与方,这些参与方是具有更多活动的合约的利益相关者。每当 A 看到超过周期边界的刻度时,它就会计算所有对方参与者(包括 B)的承诺。因此,A 为 B 计算的承诺比 B 为 A 计算的承诺更频繁。至关重要的是,A 除非看到来自 B 的承诺,否则无法进行修剪,因此 B 不太频繁的承诺会阻碍 A。幸运的是,B 通过从 A 接收到的承诺来观察刻度,并且如果由于某种原因速度不慢,则应该及时发出承诺。 B 的承诺的期末与 A 的期末相同或更高(除非 B 同时发布了另一个已涵盖该期末的承诺),因此 A 可以在收到 B 的承诺后立即进行修剪。

值得指出的是,不活跃的参与者不会发出承诺,因为它看不到时间的流逝,因此在变得活跃之前无法修剪其历史记录。

哈希生成

参与节点需要有效地将 ACS 状态汇总为承诺,以便承诺生成不会成为瓶颈。一种低效但简单的方法是将整个共享 ACS 作为承诺的一部分发送,而不是散列。这在计算上会很便宜,但在网络带宽方面却非常昂贵,因为 ACS 可能很大。一种对带宽更友好但计算效率低的方法是每个参与者节点在每个周期结束时遍历其 ACS,并根据每个对方参与者将共享的活动合约汇总到哈希中。这种方法会使参与者节点在每个纪元结束时超载。相反,每个参与者节点都会汇总该时间间隔内发生的 ACS 更改,并维护每个利益相关者组的 ACS 的运行哈希。每个利益相关者的分组可确保每个 ACS 更改仅处理一次。具体来说,每次 ACS 更改时,哈希都会添加或删除合约 ID(用于验证内容)以及合约的重新分配计数器(用于识别此合约的确切(取消)激活):创建、存档或在同步器之间重新分配的合约的重新分配实例。哈希函数是同态的,因为合约停用会抵消激活,因此运行的哈希可以增量更新。

一个周期结束时的最终承诺计算如下。对于每个对方参与者,参与者节点收集其与对方参与者共享的利益相关者组的所有非空运行哈希,并将它们添加到同态哈希中。承诺本质上包含两级同态哈希:首先将 ACS 的哈希更改为利益相关者组哈希,然后将利益相关者组哈希哈希为承诺哈希。这种两级散列的原因是它可以优化更新承诺和调查不匹配,我们稍后将对此进行描述。之后,参与者节点通过应用加密哈希来进行压缩,从而显着减小同态哈希的大小。

承诺是由参与者节点签名的加密哈希值,具有以下属性:

  • 抗冲突:由于承诺是哈希值,因此具有不同 ACS 状态的两个参与节点不太可能计算出相同的承诺。
  • 原像抵抗:给定承诺,任何人(特别是对方参与者)都很难创建符合所提供承诺的 ACS 状态。
  • 第二次原像抵抗:一旦传输了承诺,并且隐式地在参与者节点修剪其状态之后,对方参与者以后就无法声明与相同承诺相对应的不同 ACS 状态。抗碰撞性意味着第二原像抗性。
  • 高效验证:给定 ACS 状态,任何人都可以轻松检查该状态是否与特定承诺匹配。特别地,承诺的发起者可以确定某个ACS状态对于发起者本身发出的承诺是否有效。
  • 不可否认:因为承诺是签署的,所以任何人都可以确定发起者是谁,并且发起者不能否认发出该承诺。

分叉的后果

Canton 协议确保诚实的参与节点之间达成一致,即,仅由于配置错误或错误才会发生不匹配。如果两个参与节点之间的承诺不匹配,那么参与节点的运营商应该调查不匹配的情况,验证并可能修改参与节点的状态。

如果一个周期导致两个参与者节点之间不匹配,那么我们就会在参与者节点的状态之间产生一个分叉。分叉可能会自动解决,否则参与节点运营商需要进行干预。

这种干预将要求所有参与的节点运营商查看他们共享的活跃合约并找到不匹配的原因。我们提供不匹配检查工具,允许参与者节点识别哪些合约导致不匹配。但是,该工具不会自动解决不匹配问题,因为参与节点操作员需要(可能通过带外通信)决定正确的最终状态是什么,然后应用更改。

只要不匹配持续存在,受影响的参与节点就无法在初始不匹配之前修剪数据。一旦一个周期与所有对手节点匹配,那么所有先前的周期都可以隐式安全地进行修剪:即使最初状态显示不匹配,分叉也不再存在。

优化

计算大量承诺的哈希值可能会影响性能,并且交换承诺会消耗网络带宽。因此,我们实施了多项优化,以减少所需的计算量和带宽。首先,不共享活动合约的参与节点既不计算也不发送承诺或期望接收承诺。然而,如果其中一个参与者节点不这么认为,则该参与者节点会发送一个承诺,这会导致另一个参与者节点输出警告ACS_MISMATCH_NO_SHARED_CONTRACTS: Received a commitment where we have no shared contract with the sender。然后,参与者节点回复一个空承诺,这会根据对方参与者的非空状态触发不匹配检查。对于具有许多没有共享活动合约的对等参与者节点的参与者节点来说,这种优化产生了显着的性能改进。此外,如果参与者节点认为其与对方参与者的共享状态为空,则它可以进行修剪,而无需确定对方参与者同意该状态为空。

其次,关于带宽,参与节点仅定期交换承诺,这限制了消耗的带宽量,而与一段时间内的合约活动无关。此外,当没有活动时,时间段也会被汇总。每个参与节点不是不断发送相同的承诺,而是简单地聚合周期并在注意到活动后发送承诺。尽管如此,如果参与者观察到任何可能不相关的同步器活动,聚合也不会发生,因为活动会触发计时,并且在这种情况下,参与者节点确实会重复交换相同的承诺哈希,尽管时间戳不同。此外,即使没有同步器活动,交换承诺也有一个下限,默认情况下每 24 小时一次。

此外,为了避免每个周期结束时网络活动出现峰值,每个参与节点都会以抖动的延迟发送承诺。延迟是均匀分布在周期长度的 0 到 2/3 之间的随机量,因此定序器不会被承诺淹没。

承诺会尽最大努力发送,但不保证交付,从而节省网络资源。这意味着参与者节点可能会错过对方参与者的承诺。然而,这不是问题,因为每个承诺在语义上都是独立的,因此错过承诺不会影响未来传入承诺的有用性。参与者节点可能会错过过去某些时间戳的一些承诺,但只要它与对方参与者就当前状态达成一致,它就可以修剪历史记录。换句话说,即使参与者节点可能不知道先前是否存在分叉,它仍然可以将历史记录修剪到肯定不存在分叉的时间戳。

第三,关于承诺计算,两级同态哈希结构允许高效的承诺更新。参与者节点对每个利益相关者运行的哈希值执行增量更新,这些哈希值在每个周期结束时按参与者节点进行分组。这意味着参与节点不必不断重新计算承诺,并且复杂性随着激活和停用的数量线性增加。

此外,当少数利益相关者群体看到合同变更而许多利益相关者群体保持不变时,这种结构可以实现有效的更新。在这种情况下,对所有利益相关者哈希进行分组并针对每个参与者节点再次对它们进行哈希处理是低效的,因为它与利益相关者组的数量成正比。相反,我们缓存利益相关者哈希值,并在承诺中仅更新那些已更改的哈希值。由于同态哈希属性,参与者节点可以从承诺中减去缓存的利益相关者缓存,并添加新的利益相关者哈希,这与看到合约更新的利益相关者组的数量成正比。

此外,两级同态哈希结构允许有效的不匹配检查。检查不匹配的参与者节点不需要整个共享合约 ID 集:参与者节点可以执行每个级别的匹配,对匹配的利益相关者承诺保持盲态,并且只需要不匹配的利益相关者哈希的共享合约 ID 集。第四,在高负载时期,交易处理落后的参与节点减少了承诺带来的开销。当观察到的排序器时间落后于一些对应参与者时,参与者节点就会落后;参与者可以从收到的承诺中的周期推断对方参与者的定序器时间。落后的参与者节点会自动触发所谓的追赶模式,在某些时期内它会跳过计算和发送承诺。同步器操作员可以通过同步器配置来控制追赶行为。追赶模式使参与者节点了解最新的交易吞吐量,同时仍然检测分叉。

第五,对于多托管方,参与者节点只需要阈值多个相对参与者发送匹配的承诺,而不是所有相对参与者。这种优化是很自然的,因为我们只需要阈值众多的交易参与者来批准交易,并因此认为合约处于活跃状态。即使某些承诺未完成,只要每个多托管方托管在至少阈值许多发送匹配承诺的对方参与者上,这就允许修剪。这对于去中心化各方尤其重要,其中一些参与节点可能是恶意的/有缺陷的。

限制

在我们的设计中,我们在性能和功能之间进行了一定的权衡。了解设计的局限性在调查错误、不匹配或其他问题时会很有帮助。

首先,承诺不捕获瞬态合约,即在同一交易中创建和存档的合约。停用会取消激活,因此运行的承诺在任何时候都不会捕获合约 ID。这种情况是使用定序器时间作为承诺期的直接结果:定序器时间粒度中没有合约处于活动状态的点,因此承诺不会捕获它。

其次,由于参与节点仅定期交换承诺,因此它们无法检测发生的状态分叉并在交换之间得到解决。一个例子是短期合约,它不是短暂的,但它是在同一时期内创建和存档的。合约 ID 在运行的利益相关者承诺中的某个时刻出现,但停用会取消激活,并且在该周期结束时计算 ACS 承诺之前合约将被删除。仅从承诺来看,这种情况与契约从未存在过的世界没有什么区别。换句话说,一段时间内的短命分叉不会被检测到。在追赶模式下,这种担忧更加普遍。

第三,两级同态哈希有一个缺点。如果参与者节点想要证明共享状态下的特定利益相关者组没有活动合约,那么它必须打开所有利益相关者组哈希以证明所有集合都不包含给定利益相关者组的合约。我们计划将来取消此限制。


本文由 CC Privacy Club 根据 Canton Network 官方文档(CC-BY-4.0)整理翻译,仅供学习;实现细节以官方最新版本为准。