数据可用性愿景
摘要
从客户端和开发者的角度来看,使用区块链的过程可分为三个高级步骤:(1) 计算任务以交易形式提交给区块链;(2) 区块链处理交易;(3) 检查产生的状态。
对于像 Flow 这样的高可扩展性平台(我们设想每秒处理数万至数百万笔交易)来说,单个区块计算期间发生的事件以及由此产生的状态变化将超出任何单个服务器的处理能力。 Flow 网络本身通过其横向可扩展的流水线架构承担起了这一庞大的计算和数据负载。然而,区块链领域通常采用的方法,即只运行一台计算机来复制整个空间和计算,在 Flow 的规模下变得难以实现。
在下文中,我们将描述 Flow 的长期愿景,即 Flow 网络的客户端和开发人员如何可靠、可信地查询和复制与他们相关的全局状态分节。我们强调,该设计具有拜占庭容错性 [BFT],如果客户需要,他们可以获得他们感兴趣的所有数据的正确性证明。
此外,Flow 的设计实现了智能手机大小的轻型客户端,无需下载或存储链历史记录,即可完全无忧地运行。
中心概念和术语
数据出口节点或边缘节点(作为归档、观察者、访问节点的集合描述符)。边缘节点跟踪链(块头),并维护执行状态和事件数据的(小)子集。
边缘节点设计的使用模式:
- 大部分时间在线,并持续跟踪新区块,获取相关状态和事件数据
- 一次接收数据,验证正确性,本地存储和索引
- 对同一存储数据执行多项操作
- 如果边缘节点长时间处于离线状态,则需要一段时间才能恢复正常;在恢复正常期间,边缘节点无法提供正常服务(恢复正常需要大量系统资源,而且最新数据尚未提供)。
轻客户端在很大程度上是无状态的。它们无需维护任何执行状态或事件数据。不过,它们可能会在本地存储极少量的数据,比如一些区块头和一些账户状态。轻客户端向用户提供的数据是按需获取的(如果客户端需要,也可以按需流式传输)。
Light 客户端设计的使用模式:
- 非常稀疏的数据访问,大多数数据只需访问一次就不再需要
- 可在最小的硬件(如浏览器插件、嵌入式硬件控制器(如 ESP32)或智能手机)上运行
- 长时间离线不会对轻型客户机造成重大影响
可信与不可信
向用户/开发人员提供正确的数据至关重要。虽然 Flow 平台无法普遍保证数据的可用性,但我们必须无条件保证数据的正确性。保证数据正确性有两种方法:
(i) 可信:用户/开发人员相信数据源能提供正确的数据
(ii) 无信任:数据源可能提供不正确的数据。用户/开发人员的软件(边缘节点或轻型客户端)必须在摄取过程中识别出数据不正确,并将其丢弃。
无信任数据访问的一般方法是,数据源在传输所需信息的同时,还提供一些加密证明,以便接收者验证数据的正确性。流的架构使这些证明具有极高的数据效率,只需要在数据源和接收者之间进行一轮或几轮通信。
唯一的要求是,用户必须在初始安装数据接收器时提供一个单一的块标头(又称 "信任锚")。
就 Flow 而言,轻客户端如何覆盖大时间段是众所周知的。从概念上讲,轻客户端可以跨时代,每个时代只需要获取 20 到 40 个块头。因此,轻客户端只需极少的工作就能浏览数周、数月和数年的时间。
一般来说,执行状态数据和事件数据与区块绑定。数据接收方的第一步是确定区块头的正确性,这需要验证共识节点在区块上签名的正确性。区块头包含对有效载荷的加密承诺,有效载荷包含执行收据和封条,而执行收据和封条又承诺状态和事件根哈希值。这些都是merkle'ized数据结构,使数据源能够有选择地生成接收者感兴趣的子结构的证明。
此外,在大多数情况下,这些证明可以由数据源分批处理,并在一条信息中传输给接收方。
长期目标
Flow 的架构可扩展至每秒超过 100 万笔交易。您可以阅读本文中的详细信息。
- 中短期目标是支持
- 超过 1 PB 大小的状态(特定高度的快照)和
- 每几秒钟产生千兆字节事件数据的网络。 - 无信任操作(包括无信任数据输出)是 Flow 的核心价值主张。很有可能,某些数据输出功能在技术上无法以无信任方式实现,或者实现这些功能的工程难度与其实用性相比过大,或者由于证明成本过高,客户在经济上无法使用这些功能。
尽管如此,我们仍努力使只能通过可信来源获得的数据输出功能尽可能小。重要的数据输出功能必须以不可信的方式提供。否则,如果核心数据输出功能只能通过受信任/中心化实体提供,我们就会大大削弱 Flow 作为去中心化、无信任平台的价值。 - 我们还希望支持可信数据出口,因为省略证明可以大大减少硬件和能源消耗。基于法律或经济激励的信任关系非常普遍,我们应该允许客户利用这种关系来提高效率和降低成本。
- 我们希望让开发人员能够以较小的成本运行自己的边缘节点,允许他们在本地访问与其相关的状态和事件数据子集。边缘节点最终必须允许以无信任的方式获取其输入数据,适用于所有流行的使用案例。
- 我们希望用户能够运行轻客户端。轻型客户端最终必须能够在所有常用情况下以不可信的方式获取输入数据。
- 低延迟数据访问。
影响
从长远来看,无信任数据访问不能以维护全部状态和/或消耗块中的所有事件为条件,因为这需要每分钟下载千兆字节的数据并维护 PB 级的状态(对于成熟网络而言)。
因此,对于长期目标 (2),我们需要支持对状态子集和事件数据子集的无信任检索。
在成熟的网络中,执行节点可能会在整个网络的能源和硬件消耗方面占据很大优势。我们设想执行节点是完整的数据中心,而共识节点和收集节点是单个商品服务器,单个验证节点可能是几个服务器的集合体。
一方面,收集器、共识和验证节点保证了去中心化。另一方面,执行节点数量少,网络的能源和硬件需求可持续。执行节点只能通过其他分散式收集器和共识委员会为其排定的大量计算工作提供动力。分散的验证节点群保证执行节点产生正确的结果。
因此,在不大幅增加网络能耗和硬件消耗的情况下,我们无法增加执行节点的数量。
数据出口网络的愿景
作为一级数据副本的验证和访问节点
从长远来看,执行节点无法单独为数据出口网络中的每个节点提供所需的执行状态和事件数据。这是因为整个网络中只有 8 个执行节点,而且可能还有数千个边缘节点和数十亿个轻型客户端。
从概念上讲,数据复制难题有一个行之有效的解决方案:执行节点将其数据复制到数量更多但仍然有限的 "一级数据副本",这些副本再复制到数据出口网络。为了使这种分层数据复制能够抵御带宽耗尽攻击和错误数据注入攻击,应为第一层复制层设置桩。
此外,我们还必须考虑到,执行节点并没有向外部世界提供数据的内在动力。经验证据表明,节点运营商一般都愿意通过辅助服务来支持他们所在的网络,即使没有直接的金钱补偿,因为他们间接受益于采用率的提高。但是,如果其节点提供的免费服务成为实质性的成本因素,节点运营商就会出于善意停止提供此类服务。因此,关键是要让执行节点的状态和事件复制成本足够低,这样它就不会成为一个明显的痛点。
这给我们带来了一个重要启示:
执行节点有向验证节点提供必要数据的直接动力。这是因为如果没有验证者的批准,执行结果就不会被共识节点封存,执行节点也不会获得奖励。此外,向验证者发送数据的成本由执行节点的奖励支付。在成熟的协议中,将有大约 60 到 250 个验证节点负责重新计算每个数据块。作为验证工作的一部分,验证节点会在本地重新生成与执行节点完全相同的数据。换句话说,对于每个数据块,网络中至少有 2/3-60=40 到 2/3-250=166 个额外节点,它们拥有边缘节点感兴趣的数据。从本质上讲,流网络已经拥有了一级数据副本,包括执行节点向其提供数据的激励机制。
一个非常合理的假设是,如果验证节点也分担了部分负载,那么为边缘节点免费提供数据的成本将足够低。
协议要求执行节点和验证节点只保留有限的历史数据
执行和验证节点中的数据寿命有限。执行和验证节点的目的是推进网络,而不是长期数据存档。
作为第 2 层数据副本的未堆叠观察者和存档节点
观察者节点和存档节点是未标记的。它们将从被标记的 Execution、Verification 和 Access 获取执行状态数据。如上所述,如果所有执行、验证和访问节点都能分担数据出口的运行负载,那么一个繁荣的生态系统所带来的隐性好处可能会极大地激励执行、验证和访问节点在没有明确补偿的情况下提供这种服务。此外,观察者节点和归档节点在默认情况下也应相互共享它们在本地存储的数据(例如,使用比特交换协议,其工作原理与比特洪流十分相似),这将进一步减少被标记节点的负载(至少是所有非绝对最新的数据)。
在混沌环境中,执行从一方到另一方的数据传输是一个棘手的问题,因为缺乏通信会出现 "渔夫的困境"(Fisherman's dilemma)。如果数据传输失败,外界就无法确定是谁的过失(至少在区块链中不记录数据请求和响应的情况下无法确定,而在这种情况下,由于数据量巨大,记录数据请求和响应是难以解决的)。
如果操作员需要,可在所有边缘节点(访问节点、观察节点、存档节点)上执行脚本
脚本执行是一项附加服务,可添加到任何边缘节点。边缘节点的所有者应能配置其边缘节点是否向社区提供脚本执行服务,或者是否只想提供私人脚本执行服务。
优化复制数据,无需等待封存
我们的目标是在数据执行后立即向外部客户端提供数据(目标 6)。等待封存不是一个长期的选择,因为封存本身会增加几秒钟的延迟。
只要执行节点对其结果做出承诺(在块中记录执行收据),我们就能相对较高地保证其正确性,因为如果后来发现数据不正确,执行节点就会被砍掉。在大多数情况下,这足以保证客户接受执行结果。
然而,对于安全关键型应用,客户可能希望等待密封。我们希望让客户可以选择保证级别,以便在安全性和延迟之间做出最佳权衡。特别是,客户机应能指定是否愿意信任某些特定的执行节点,并在结果可用时立即接受它们。 另一个实际有用的选择是,客户可以指定他们希望至少有k 个执行节点在接受同一结果之前已对该结果做出承诺。极少量的可用条件可能已经非常有用了。
为观察状态转换(即利用事件)提供丰富的支持
背景:
Flow 是一个计算平台,其核心目标是保持一个执行状态,并通过状态转换使该状态随时间不断演进。通过 cadence 脚本可以很好地观察状态(在程序块结束时)。但状态转换缺乏可观察性。我们有事件可以揭示状态转换的信息(类似于传统软件的日志信息)。
影响(假设)
在很多情况下,链上发生的事情与外部世界息息相关。但是,开发人员很难(概念上复杂,工程上繁重)建立与链上发生的事情相关的系统。因此,我们鼓励开发人员将他们的逻辑转移到链外,转移到一个他们可以控制并且很容易观察到的环境中。然后,Flow 就像一个数据存储系统,所有逻辑都在链外进行,只有结果才会提交回链上。
然而,将逻辑移到链外破坏了 Flow 的可组合性价值主张。如果链上的逻辑很少,那么就没有什么可以在上面进行组合或构建。可组合性的价值关键取决于观察状态转换的良好平台体验,即支持数据丰富的事件。
长期愿景:
过滤和索引作为边缘节点上的一项服务,包括无信任事件检索。
以下过滤功能对解决大多数用例具有广泛的潜在作用:
- 按事件类型过滤
- 根据值对事件字段进行二次过滤(分级可能是一种可行的方法,类似于 prometheus)
- 事件类型层次结构(可能需要额外的节奏功能)。这样就可以查询 "给我所有 NFT-mint 事件"。从概念上讲,这与编程语言中的接口非常相似,只是应用于数据结构。当开发人员指定其事件为 "NFT-薄荷类型 "时,该事件必须至少包含抽象类型中指定的数据字段(可能还会更多)。
- 支持流式传输,客户可以向边缘节点注册网络钩子和相应的事件过滤器,并将他们感兴趣的事件子集流式传输给他们
事件索引和汇总(见下一节)
本地数据索引和聚合
区块链领域现有的数据索引解决方案大致可分为以下两类:
集中式(例如:炼金术):
- 需要信任
- 受保护主义、特殊利益、寡头垄断等因素的影响
- 非常节省硬件和能源,因此也非常节省成本
- 可以涵盖所有可计算的用例
分散式(例如:图表)
- 允许分散访问
- 促进可组合性
- 导致更高的硬件和能源开销,因此成本效益较低(为保证分散式平台的安全,需要更大的冗余度)
- 开销(更高的冗余度)将使相当一部分计算密集型索引和聚合用例望而却步
公理:
我们认为,分散式数据索引和聚合具有分散性和开放性,并能抵御网络攻击和自然灾害,因此非常有用。
分散式数据索引和聚合的通用方法:
计算平台(第一层区块链)与去中心化的数据索引网络(如图表)相连接。
缺点
- 桥接会产生高延迟
- 开发人员的开销很大,因为他们必须为两个生态系统编写代码
- 使用开销:原始区块链和图谱各有自己的代币
- 原始区块链上的智能合约无法使用指数和聚合,因为它们生活在不同的生态系统中
洞察力:
- 第一层区块链会计算一些东西。随后,"图谱 "摄取状态+事件的子集,并执行索引和聚合。从本质上讲,我们有一个第一层计算平台,其结果由第二层计算平台摄取,以便进行后处理。
- 这种耦合两个计算平台的方法之所以发展起来,是因为区块链通常太弱,无法处理索引和聚合所需的计算负载和数据存储。因此,人们接受了耦合计算平台的大量开销和性能成本。从概念上讲,这只是分片的另一种情况。
长期愿景
Flow 的架构可处理大量计算负载并存储海量状态。与大多数(所有?)其他基于区块链的计算平台不同,Flow 将有能力在平台内原生运行数据索引和聚合。事实上,许多索引和聚合计算特别适合并发执行,这对 Flow 的大型执行节点非常有效。
与其让开发人员为两个生态系统编写代码、处理两个代币、高延迟以及无法正确访问原始第一层智能合约中的索引和聚合,我们不如在 Flow 中原生提供索引和聚合功能。这非常符合 Flow 的精神,因为我们不会将复杂性外包给开发者,而是将其吸收到平台中。这样,平台就能一次性解决问题,而不是让开发人员反复解决同样的问题。我们提高了 Flow 平台的实用性,使开发人员能够专注于他们的创意,而不是把时间花在绕开平台限制上。
总之:这样的设计无法保证正确性。这样的系统极易受到错误数据、垃圾邮件和诈骗的影响,因此很可能无法提供任何实用性。
原因是
- 数据索引和聚合一般需要转折性的完整计算
- 输入(来自区块链)的正确性通常可以通过加密证明来确定
- 但是,数据索引和聚合算法的真实执行并不容易验证。因此,由此产生的索引和汇总数据很容易被篡改和审查。
- 图形通过引入令牌、要求索引器节点进行标记和引入冗余来解决这个问题。这样,他们就可以砍掉有问题的索引器节点,并强制执行正确的结果。The Graph 的网络与区块链有很大的相似之处,特别是在执行正确性方面。
Flow 已经具备了执行真实执行的所有机制,以及处理这种负载的计算能力。
向最终愿景逐步演变
当前状态
- 数据只共享给观察者和存档,一旦封存
- 观察者和归档节点必须摄取每个区块的完整状态三角洲(全部或无)
- 观察者/存档节点的无信任(加密验证)数据摄取
- 观察员/档案节点为社区提供可信的、基于投票的数据访问 API
重要意见
从概念上讲,只有在向别人证明数据正确性时才需要三元组。如果有一个完美的本地数据存储系统,观察者/存储节点理论上根本不需要三元组(除非该节点想为其他人生成状态证明)。从概念上讲,保存一个版本控制的键值存储空间就足以执行脚本。
即使没有三元组,观察者/存储节点也能对其输入数据进行加密验证,只要它能摄取每个块的完整状态迭代和所有事件。这需要对分块数据包和验证节点进行一些修改,但这只是一个中等程度的工程提升。
观察者/存档节点使用其本地三元组来
- 重新计算,从而验证输入数据的正确性
- 确定大块数据包中的寄存器是只被读取还是被更新
或者,观察员/档案馆可以
- 对块数据包(或其下载部分)进行散列,并验证这些数据是否与执行节点承诺的一致。由于验证节点也会检查分块数据包,因此无需三元组就能确定分块数据包中寄存器的正确性。
- 在目前的形式下,块数据包列出了所有被触及的寄存器,但并没有区分读取未修改寄存器和更新寄存器。不过,在块数据包中,我们可以很容易地将更新的寄存器与只读的寄存器区分开来。这样还可以减少观察者/存档节点的网络负荷,因为它们可以有选择性地只下载更新的寄存器。
- 这就需要对块数据包进行一些小的重组,并可能在验证节点中进行一些小的额外检查。然后,我们就不再需要观察者/存储节点中的三元组了(除非我们想为客户端生成状态证明)。
目前,执行状态和事件数据还很小。因此,从概念上讲,即使在商品硬件上也有可能复制整个状态和事件数据。
需要注意的是,我们目前很容易受到缓慢、隐蔽的数据衰减的影响。可能的来源是磁盘错误、数据库错误或观察者/存档节点的错误。不过,这主要是一个长期问题。
此外,目前在观察者/存档中使用的三元组也能很好地解决这个问题,因为我们只在将状态写入数据库之前进行验证。我们将更新寄存器的键值对写入数据库,其正确性同样可以通过块数据包哈希值来确认。即使使用三元组,磁盘错误或数据库错误导致的后续数据损坏目前也不会被发现。
进化 1(接近完成)
- 结束目前正在进行的Archive / Observer 节点重构→ V2
(现有代码的成熟和稳定性改进) - 边缘节点在商品硬件上运行[2023 年 6 月完成]
从 DPS 节点移除三元组。相反,它们使用执行数据哈希值对入站数据进行加密验证。
- 在边缘节点上执行脚本
- 索引作为边缘节点向客户提供的一项服务
- 根据事件类型和智能合约在边缘节点上进行可信 事件(预)过滤的初始版本
-为事件访问 API添加可信 流支持,客户可根据事件类型或发布事件的智能合约订阅事件
- 优化数据复制到边缘节点(无需等待封存→减少延迟)。
详情:
- 一旦执行节点将 B 的收据嵌入到链中,即摄取最终完成的区块 B 的结果(持有收据的降序区块无需最终完成)
- 仅在有 1 个以上执行节点提交相同结果的情况下向客户端报告结果(与当前访问 API 的行为一致)。
- 网络层加固(BFT 工作流)将允许增加无权限、潜在恶意访问节点的数量(可能多达 20 个拜占庭访问节点 + 更多诚实访问节点)
- 连接流媒体和事件过滤的边缘节点内部应用程序接口
观察员/档案节点为社区提供可信的、基于投票的数据访问 API
- 观察者/存档节点的无信任(加密验证)数据摄取
- 边缘节点仍然复制完整的状态和事件数据(很有可能,这些数据仍然足够小,因此使用商品硬件复制完整的数据是可行的)
展望:
2023 年,我们将开发二进制帕特里夏三角洲(又称 "新三角洲")。我们预计从头到尾的开发至少需要 6 个月,实际可能需要 9 个月。
二进制 Patricia Trie 将支持在数据库中存储 try(目前,trie 完全位于内存中)。
二进制 Patricia Trie(支持硬盘存储)将解锁各种极具战略意义的功能:
- 以无信任方式进行服务器端事件过滤
- 边缘节点只下载和维护执行状态和事件的子集,这样,即使执行状态变得非常庞大,区块产生大量事件,边缘节点也能继续在商品硬件上运行
- 为社区提供不可信的数据检索
- 支持无托灯客户
- 为社区提供可信的脚本执行(详情:脚本执行:愿景与展望)
有了二进制帕特里夏三角形,我们就能在 2024 年开始构建无信任基础设施 👇
随后的进化步骤
- 将验证节点列为一级数据副本
- 缓解数据衰减(建立在磁盘上二进制 Patricia Trie 的基础上)
- 边缘节点可以无信任方式维护状态和事件数据子集(需要基于三元组的证明,包括数据完整性证明)
- 相互之间实现无信任的数据共享
- 为社区客户提供经过过滤的事件流,值得信赖
- 事件类型系统允许按类别过滤事件
- 通过事件中的字段值进行二级过滤(例如,只给我 NFT-mint 事件,其中稀有度为 "传奇")
- 第一个版本可以信任
- 无信任版本会很好,但可能太复杂(可能需要特定的节奏支持,开发人员将指定桶作为事件类型定义的一部分)。
- 无信任脚本执行
- 社区客户可选择所需的安全级别:
- 要求密封结果
- 可以不密封结果,但必须有来自k 个不同执行节点的一致收据(k值由社区客户决定)
- 只要是来自客户信任的执行节点的不密封结果即可(受信任的 EN 列表由客户指定)。
智能手机大小的轻型客户机
当设想在嵌入式硬件(包括智能手机)上运行的轻型客户端时,有三个主要挑战需要解决:
- 轻客户端可合理消耗的 CPU 周期、内存和存储空间极其有限。你可能更喜欢用智能手机的存储空间来存储照片,而不是数千兆字节的链数据。
- 要让轻客户端对普通终端用户有用,它就必须处理长时间离线的问题。即使允许轻型客户端通过操作系统和用户行为不断验证链的进度,这样做也会以令人无法接受的速度耗尽电池。
- 最后,轻型客户端必须能够快速有效地追赶多天的链条进度。下载所有区块是不可能的。试想一下,从为期三天的露营归来后,您急切地想查看一些 NBA 巅峰时刻的交易是否成功,但您的手机却花了 20 分钟来下载和验证所有遗漏的区块头......然后就没电了。
这些功能都是通过共识追随者(Consensus Follower)实现的。简而言之,共识追随者是一个用于无信任地跟踪共识进展的库。共识跟随器独立应用共识规则,并在本地断言区块的终结性。从本质上讲,它保护了高层处理逻辑,避免任何恶意节点发送无效区块。与完全共识参与者不同,共识跟随者不需要验证区块的全部有效载荷,而只需验证区块的头部,利用共识节点已经完成的验证工作。
Flow 将时间划分为若干个纪元,每个纪元为期一周。在这一周内,被授权参与网络的节点数保持不变。例如,如果某个节点被砍掉,网络可能会取消其提出区块的权利,但不会在纪元中期增加新的节点。
在纪元转换时,被授权运行纪元 N 的节点会将区块链的控制权移交给纪元 N+1 的节点。共识追随者的一个有趣特点是,它只需要来自第 N 个纪元的几个区块,就能断言来自第 N+1 个纪元的任何区块头的有效性。下图说明了这一过程。如果您对更详细的工作原理感兴趣,我们向您推荐这篇文章。
在一个纪元中,大约有 460,000 个区块最终完成,而共识追随者只需检索其中 0.005% 的区块。因此,跟随者可以快进几个月甚至几年的区块,所消耗的计算和网络资源几乎可以忽略不计。
此外,考虑一个纪元(过去或当前),追随者知道该纪元的授权节点。追随者可以通过下载一个小的链段并断言其有效性和终结性,无须知道任何祖先区块,就可以在属于该纪元的某个高度上无信任地检索状态根哈希值。当知道某个区块的状态根哈希值时,就可以利用梅克尔证明(Merkle proofs),以不可信的方式有选择地检索部分状态。
了解有关福禄的最新信息。
了解有关福禄的最新信息。