在 DApp 开发中的链上和链下同步问题
在使用基于区块链的 DApp 服务时,用户可能会看到一个屏幕,指示交易已完成。我曾想过,“在交易可能被取消的情况下,通知用户交易已完成是否真的没问题?如果交易被取消会发生什么?”区块链服务是如何在处理阶段通知用户交易已完成,并在交易被取消时如何通知用户的呢?
今天的文章“ÐArcher: 检测去中心化应用中的链上-链下同步错误”讨论了链上和链下之间的同步错误,定义了两种链上-链下错误,并通过实验展示了实际基于以太坊的 DApp 中发生的链上-链下同步有多少发生错误。
图 1. DApp 结构
随着允许可编程智能合约的以太坊的推出,去中心化应用(DApp)服务应运而生。DApp 指的是在区块链上运行的应用程序,包括 DeFi(去中心化金融)和 CryptoKitties 等众所周知的示例,都属于 DApp。DApp 由链上和链下组件组成,如图 1 所示。链上组件由存储数据并更新其状态的智能合约组成,而链下组件由与用户和中心化服务交互的前端客户端组成。
区块链的特点之一是最终确定性。最终确定性意味着一旦交易被执行和处理,就无法撤销。在区块链中,如果出现分叉,将应用最长链规则,选择最长链并取消与较短链相连的区块和交易,这可能会破坏最终确定性。然而,随着时间的推移和区块的增加,区块被取消或撤销的可能性会降低。换句话说,在包含我的交易的区块之后链接的区块越多,最终确定性就越高,这意味着不必担心我的交易会被取消或撤销。每个区块链都有一定数量的区块来确保最终确定性。对于比特币,这是 6 个区块,每个区块平均需要 10 分钟,约 1 小时后确保最终确定性。以太坊也在 6 个区块后保证最终确定性,每个区块平均需要 12 秒,约 1 分 12 秒后确保最终确定性。
图 2. 以太坊交易生命周期
图 2 表示了以太坊交易的生命周期。用户在链下创建的交易并发送到区块链后被添加到交易池中,进入待处理状态。然后,当被包含在一个区块中时,交易被执行(已执行),并在当前区块后生成足够数量的区块后达到最终状态(已最终化)。理想情况下,交易应始终在没有问题的情况下达到最终状态,但如图所示,每个阶段都存在交易被删除或其执行被取消的可能性。
在待处理状态下,交易可能会在两种情况下被丢弃:
执行阶段中的撤销(已撤销 - Reversed)状态是由于区块链分叉而可能发生变化的状态,如前所述。如果包含交易的区块被取消,则取消区块内的交易将被撤销,返回到交易池中等待在已撤销状态下执行。与待处理状态类似,已撤销状态下的交易也可能被删除。
文章揭示,在 Etherscan 上对以太坊交易进行四个月的调查显示,以太坊上每秒发生的交易数量(TPS)为 32.5,但实际交易处理能力为 16.4 TPS,超过一半的交易无法立即执行。研究还发现,由于分叉导致的链重组平均每 24.43 个区块发生一次(约每 11.06 分钟一次)。每小时平均有 16.69 笔交易恢复到已撤销状态,这个问题不容忽视。因此,在开发 DApp 时,必须考虑非确定性交易,以避免链上-链下同步错误。
链上-链下同步错误是指在链上和链下状态之间缺乏一致性时发生的错误。如前所述,考虑到交易的生命周期,很明显交易在待处理状态时可能会被删除,即使在待处理状态下,已执行的交易也可能会被撤销和删除,如果包含交易的区块被取消,则交易的非确定性特性得以展示。然而,DApp 开发人员可能在开发过程中未考虑交易的非确定性特性,导致在其服务中提供不正确的信息。链上-链下同步错误可能导致链下服务显示不正确的状态,使用户发出错误的请求或操作,或导致费用的浪费。
文章将这些问题定义为链上-链下同步错误,并描述了这类错误的两种类型(Type-1 和 Type-2)。
Type-1 错误:
图 3. Type-1 错误
图 3 说明了 Type-1 错误发生的情景。当交易处于待处理状态时,如果链下更改其状态以指示交易已完成,而实际上交易仍在待处理状态,并且随后如果矿工未将交易包含在区块中,从而未处理它,则会出现链上-链下同步问题,这被定义为 Type-1 错误。
Type-2 错误:
图 4. Type-2 错误
图 4 说明了 Type-2 错误发生的情景。当交易从待处理状态移动到已执行状态后,如果链下更改其状态,则可能发生 Type-2 错误。人们可能会认为状态不会改变,因为交易已执行,但如果发生分叉并且未选择包含交易的区块,则交易的状态将被撤销和删除。因此,在已执行状态下更改链下状态可能导致链上-链下同步问题,这被定义为 Type-2 错误。
ÐArcher 测试框架利用测试 Oracle 有效地检测错误。
测试 Oracle 是一种软件测试技术,它使用预定义的真值与测试结果进行比较,以确定它们是真还是假。Type-1 错误的测试 Oracle
断言 1. 对于每个交易𝑡,𝜎(𝑡,已创建) ≠ 𝜎(𝑡,已完成)意味着 𝜎(𝑡, 待处理) ≠ 𝜎(𝑡, 已完成)。
Type-1 错误发生在 DApp 状态变化过快,无法反映交易(t)已被执行并在添加到交易池后完成的情况。在断言 1 中,𝜎(𝑡,𝑠)代表了交易 t 处于状态 s 时 DApp 的链下状态。𝜎(𝑡, 已创建) ≠ 𝜎(𝑡, 已完成)意味着尽管交易创建时状态可能会改变,但不应该变为已完成状态。同样,𝜎(𝑡, 待处理) ≠ 𝜎(𝑡, 已完成)意味着虽然状态可能会从待处理改变,但不应该变为已完成。因此,如果链下状态在交易处于已创建或待处理状态时变为已完成,这表明存在 Type-1 错误。
Type-2 错误的测试 Oracle
断言 2. 对于每个交易𝑡,𝜎(𝑡,待处理) =𝜎(𝑡,已撤销)。
Type-2 错误指的是当交易(t)进入已执行状态时,链下状态可以发生变化。然而,如果链路被取消,导致交易恢复到已撤销状态且链下状态不变,这表明存在错误。因此,断言 2 意味着当交易变为已撤销时,其状态应与待处理时相同。违反断言 2 表明存在 Type-2 错误。
断言是开发人员认为必须始终为真的逻辑表达式。在代码中实现断言并检测违规情况表明存在错误或问题。
该图示了ÐArcher 的工作流程。首先,前端资源管理器中的 UI 事件触发一个交易,然后由受控区块链执行。ÐArcher 监视链下状态以响应交易状态更新以检测错误。在图中,受控区块链是一个可以通过已创建、待处理、已执行、已撤销、再次已执行和最终已完成状态序列管理交易生命周期的实现。
本文进行实验以回答以下三个问题:
表 1. 实验中使用的 DApps 列表
在实验中,本文从 GitHub 上具有 100 颗星以上的 DApp 项目中选择了 11 个项目,这些项目被实现为 Web 应用程序,并使用可部署在本地受控区块链上的智能合约。选定的 DApps 被部署在本地受控区块链上进行实验,将ÐArcher 与基线-1 和基线-2 进行比较。
本文在本地受控区块链上部署了选定的 DApps 进行实验。将ÐArcher 的延迟设置为以太坊的平均区块创建时间 15 秒,并重复测试 10 次以减少随机性。
表 2. 实验结果
TP: 真正例(实际值和测量值都为真的情况)
FP: 假正例(实际值为假但测量值为真的情况)
FN: 假负例(实际值为真但测量值为假的情况)
Pre: 精确率
Rec: 召回率
Acc: 准确率
RQ1(错误检测能力)
RQ1 评估了ÐArcher 能够有效检测错误的能力。表 2 呈现了ÐArcher 的实验结果与基线-1 和基线-2 的比较。当传输了 3,134 笔交易时,检测到了 369 个 Type-1 错误和 1,862 个 Type-2 错误。此外,还发现了 16 个 Type-1 错误,这些是假正例(FP),表明即使实际上没有发生 Type-1 错误,也检测到了 Type-1 错误。此外,假负例(FN),即ÐArcher 未检测到的实际错误,Type-1 错误为 52 个,Type-2 错误为 264 个。尽管数据存在一些不准确性,但ÐArcher 仍表现出高精确度(99.3%)、召回率(87.6%)和准确率(89.4%),有效地检测了 DApps 中的链上和链下同步错误。
RQ2(我们 Oracle 的效力)
RQ2 比较了本研究设计的两个 Oracle 与两个基线的效力。基线-1,ContractFuzzer,和基线-2,通过报告 JavaScript 中的运行时错误来检测错误。表 2 显示,基线-1 将 7 笔交易检测为 FP,表明它无法检测到链下-链上同步错误。基线-2 检测到了 257 笔交易。然而,基线-2 的整体精确率、召回率和准确率分别为 56.9%、10.1%和 20.7%,相较于ÐArcher 效率更低。因此,本文提出的 Oracle 在检测链下-链上同步错误方面比现有 Oracle 更有效。
RQ3(有用性)
RQ3 讨论了ÐArcher 对开发人员的实用性。在将ÐArcher 检测到的错误报告交付给每个 DApp 的开发人员后,确认了 15 个错误中的 6 个,并修复了 3 个。根据开发人员的反馈,ÐArcher 对于检测链下-链上同步错误是有用的。
本文定义了链上和链下之间的同步问题,并设计和开发了用于检测链下-链上同步错误的 Oracle 和ÐArcher 框架。通过使用开发的框架进行的实验结果显示,许多 DApps 存在链下-链上同步错误,并且开发的错误检测框架和 Oracle 能够检测到这些错误。本文的作者指出,创建 DApps 的开发人员花费大量时间测试和验证智能合约,但往往忽视了交易生命周期。忽视交易生命周期可能导致链上和链下状态之间的差异,为用户带来意外结果和浪费费用。因此,DApps 的开发人员需要更新链下状态,考虑交易生命周期以向用户提供正确信息。
迄今为止开发的许多 DApps 在将交易添加到交易池或执行后立即通知用户交易已处理,如果交易后来被取消则不采取任何行动。持续检查链下状态的链上状态可能会很困难,等待交易完全完成也不总是答案,因为确保最终确定性可能需要很长时间。然而,作者认为有必要在交易执行时通知用户,因为交易完全取消的可能性很低,因为包含在区块中的交易即使链发生变化也可能保留在区块链中。此外,在不保证交易最终确定性的区块链上开发 DApps 时,开发人员需要考虑何时更新链下状态以及如何通知用户如果交易被取消。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!