mt logoMyToken
总市值:
0%
恐慌指数:
0%
币种:--
平台 --
ETH Gas:--
EN
USD
APP
Ap Store QR Code

Scan Download

深度解读无状态概念

收藏
分享

早在2017年以太坊创始人Vitalik就在以太坊开发者大会(Devcon)上介绍了无状态(Stateless)客户端的概念,以解决日益减少的链上状态存储所面临的公共链上面临的链上数据增长问题。该概念被认为是区块链摆脱状态膨胀的理想解决方案,并且在过去几年中,通过Alexey Akhunov和Igor Mandrigin等人的不断深入研究,无状态概念变得更加丰富。本文旨在对“无状态”、“状态过期”和“状态清理”等概念的最新研究成果,以及如何将这些概念应用于实践进行初步解读。

一、背景

要了解无状态客户端是什么,必须首先了解无状态客户端概念的背景。

区块链是去中心化的,既不隶属于强大的机构,也不属于个人私有,这是“公共”的。公共所面临的最大挑战是如何使有限的资源尽可能高效节能,避免整个公共块因资源无效占用而变得效率低下甚至消失的悲剧。以以太坊为例,随着账户和合约数据量的不断增加,目前所有节点上保存的状态数据已经超过2TB,不断增加的状态数据对所有公链都带来了一系列风险。

1、提升节点运行成本

不断增长的状态数据不可避免地需要全节点在存储上投入越来越多资金,而随着TPS的不断提高,在数据呈指数增长的情况下查询或插入新的Key势必会增加IO开销(即使是使用leveldb这样的键值数据库),所以全节点必须不断优化和升级其硬件以满足出块(矿工)的要求或验证节点的要求。

2、去中心化的威胁

Vitalik曾将当前的交易计费机制描述为一次性gas支付,对网络施加永久的持续成本,当前的每状态存储区块链不会为长期存储用户数据收取额外费用,这意味着对于运行完整节点的节点来说,没有额外的财务激励。理所当然地,随着成本的增加,网络中能够提出区块(矿工)或验证区块的节点将越来越少,这将在很大程度上威胁到整个网络的去中心化,并对整体安全构成重大威胁。

3、DDoS攻击风险增加

在以太坊上,交易以Gas为基础收费,虽然矿工主动以Gas价格(EIP1559之前)打包交易,但一般来说,价格取决于网络的繁忙程度,而不是代币的实际价格。这种不匹配的糟糕结果就是,当代币价格较低时(至少从稳定币/法定货币的角度来看),在网络上发布交易的成本非常低,这很容易受到使用少量成本的恶意攻击,用大量垃圾邮件交易填充网络状态数据。正如我们之前所说,交易的发送方只支付一次,但会给网络带来永久的负担。

这些问题几乎是目前所有公链都存在的,无状态概念正是在这种背景下诞生的。

二、无状态概念

无状态 念可以简单地概括为用带宽开销换取存储开销,最初由Vitalik用以下术语描述。

STF(状态转移函数):状态转移方法

S(state):状态,即与账户关联的数据,如余额、随机数等。

B(block):区块,也可以理解为当前交易在区块链中的状态存储,可以描述为:通过STF转换函数和block(或交易)将状态S转换为状态S'。

假设我们将MPT树中所有账户的根(State Root)作为S和可以证明该区块或交易需要被访问的所有Merkle分支的一组Roots作为见证数据W(Witness)。

上面的等式可以描述为:可以有这样一个状态转移函数STF',它通过将前一个区块状态S的根节点StateRoot、区块或交易B以及验证B所需的见证数据W作为输入来计算新的状态S′。

这个公式的意义在于,验证者只需要存储最新的StateRoot就可以对一个区块或交易B进行验证,完全不受状态数据的拖累,完全不受状态膨胀的影响。

简而言之,无状态概念是期望节点在不访问或较少访问状态数据的情况下,通过验证区块或交易的见证数据来完成区块或交易的验证,从而达到减少区块或交易存储的目的。

但是,并非所有节点都没有状态数据是可以接受的,用户必须能够访问当前状态信息(例如账户余额、nonce等)才能根据最新状态发起交易,因此用户数据(状态)必须以某种方式存储,因此Vitalik提出了无状态客户端和状态过期方案。

三、无状态客户端

根据节点划分的不同,将网络上的客户端分为无状态客户端和无状态客户端。

1、弱无状态

区块生产者需要保留状态数据才能生成区块见证数据见证,而区块验证者不需要状态数据而只需要验证见证,即区块生产者节点是状态客户端,区块验证者是无状态客户端。

2、强无状态

生成区块的节点和验证区块的节点都不需要维护无状态客户端,生产者生成一个新的区块并根据交易的见证人验证交易,因此只需要交易的发送者维护全部的状态客户端确保它可以提供见证。

然而,不管节点之间的分工如何,随着账户数据越来越多,交易或区块的见证会越来越大,增加了网络的负担,因此这种解决方案可能不是最优的解决方案。

四、状态到期

一个更温和的解决方案是“状态到期”,它假设必须连续访问帐户才能保持“活动”状态,并且长时间未访问的帐户将变为“不活动”(或“过期”)。一般原则是,除非状态对象被明确更新,否则它会以某种方式变为非活动状态。因此,任何创建新帐户对象(或刷新现有帐户对象)只会在有限的时间内给网络带来负担;一旦帐户被停用,它将消失在历史记录中。

状态到期可分为以下几类:

1、状态租赁

状态租赁旨在为状态滥用问题提供一种经济的解决方案,其中每个区块的提议者按照约定直接从每个账户的余额中扣除状态租赁费,当账户余额减少为零时,该账户就被注销了。

2、时间租赁

时间租赁不向用户收取租金,而是为链上的每个帐户存储一个生存时间值,该值随每个区块而减小,当帐户的生存时间值减小到0时,该值将被清除。该值可以通过特定的交易来增加。

3、访问刷新

为每个帐户存储一个生存时间值,每个区块递减并在帐户的生存时间值减少到0时清除。当对该状态进行读取或写入时,该值会自动增加。

似乎“通过访问刷新”方法最有意义,因为它不需要复杂的激励策略,并确保活动状态的大小有明确的上限(区块Gas限制/达到状态对象的Gas消耗量x状态存在的时间长度)。在实践中,状态过期仍处于研究探索阶段,因为每个新生成的状态都需要遍历所有帐户才能确定是否过期,这大大增加了状态维护开销和成本。

五、状态清理

正是由于状态过期的不切实际,通过特定规则定期清理状态的机制越来越受到研究人员的关注,其中半无状态Semi-Stateless和再生机制Re-genesis方案最具代表性。

1、半无状态

半无状态也是一种无状态方案,其基本流程如下:

(1)每个节点的最新状态为T1,节点每次验证或执行区块B时都会提供额外的见证数据W1、W2……这些见证数据可以将T1转换为T2;

(2)在T1上依次执行W1、W2、……最终得到T2,过程中不需要查询数据库;

(3)在T2上执行块B,同样不查询数据库;

(4)留T2待后续使用,T1和之前的状态都可以清理掉。

根据mandrigin的半无状态初始同步实验,与完全无状态相比,使用该解决方案显着减少了区块同步期间见证数据的大小。

2、再生机制

再生机制可以被认为是一种“定期清理”解决方案,最初受到Alexey的Cosmos升级的启发,现在是最热门的无状态解决方案之一。

该方案通过哈希周期性地指定区块高度,对链上状态数据进行快照,同时清理状态数据,再生后的区块根据前一个区块的哈希记录新的状态数据和见证数据见证。该方案提出了显式状态和隐式状态的概念。

(1)隐式状态

如果您在任何给定时间从另一端的节点收到块数据N,则另一端假定该节点已经拥有验证块中交易所需的所有状态数据,并且已经同步到块N-1,即另一方假设您拥有状态,因此不会传递状态数据本身。

(2)显式状态

如果您在任何给定时间从另一端的节点收到块数据N,则另一端假定该节点没有隐式状态,因此该块不仅与块数据一起发送,而且还与该节点的见证人一起发送。

再生机制方案会定期将链上的当前数据重新生成为32字节的哈希值,再生后的每个区块都需要所有对应方发送“显式状态”,但随着状态数据的增长,见证数据变得越来越小,从而实现存储开销和见证数据开销之间的平衡。

再生机制的目标:

  • 对于每生成N个块,会将所有状态归零并仅保留根哈希

  • 再生机制启动不要太频繁,Ether上的推荐设置是每100万或1000万个区块

  • 交易发送方需要提供明确的状态(作为交易见证)

  • 交易发送方根据交易规模为交易支付Gas费用

  • 交易发送者必须保留他们感兴趣的合约/账户的创世前启动状态

  • 如果由于显式状态不足导致交易失败,则可以将为该交易提供的证明添加到隐式状态,以便下次发送交易时无需提供相同的证明

  • 来自交易证明的显式状态通过智能合并机制与区块中较早运行的交易生成的隐式状态合并

此选项具有以下优点

  • 改变交易发送者和基础设施节点之间的激励平衡,从而增加状态存储的去中心化

  • 通过再生限制状态增长

  • 允许使用交易见证并简化每个交易见证的Gas定价

六、如何设计过期机制

对于大多数区块链来说,都有通用的用户账户(外部账户)和合约账户。对于外部账户,前面提到的状态过期方案很好理解,也很容易实现,但是对于那些存储在智能合约存储中的数据,如何设计过期机制呢?由于合约中的存储槽数是无限的,用户可以在存储中存储无限的数据,这需要考虑。

选择限制用户使用无限存储——需要设计复杂的经济方案,将状态租金转嫁给用户。

选择修改现有的存储模型——将合约的存储放入一个由create2命令创建的新合约来管理状态,这可能导致“复活冲突”,因为状态可能不在链上(见下文)。

当状态过期或被清理时,我们是在原始树上将过期的键标记为“过期”,还是将所有过期的键从原始树移动到单独的树中?

标记过期的优点是它的工作方式和现在几乎一样,标记“过期”相对简单,但问题是标记需要节点存储额外的“中间信息”,即不适用于Verkle trie,并且除了Merkle-proof之外,过期节点还必须由额外的见证人证明。

二叉树解决方案不需要每个节点额外的代币,不需要额外的见证人证明,也没有“复活冲突”。但是,它存在对当前协议改动过多的问题,需要额外的程序使数据过期。

如果A用create2创建了一些合约,但是状态过期了,之后A又用create2创建了合约,这样新的合约和旧的合约发生冲突,所谓的“复活冲突”,应该怎么办?

  • 账户合并——将旧合约的ETH加入到新合约中,存储和代码与新合约合并,甚至旧合约的代码也可以指定冲突合并的逻辑。

  • 抑制复活——调整create2操作码实现,使其在不同时期创建不同的账户地址(例如通过year再生机制,不同的years会创建不同的地址)。

  • 为账户添加标识位——同一位置只能创建一个合约,重复创建将被拒绝。

  • 要求new create2在启动时进行自证明——类似于添加标识位,不同之处在于标识符被添加到与帐户无关的位置。

发送交易的用户或提出区块的矿工面临着获取生成见证所需的状态数据的问题,简单的想法是发送交易或发布区块的节点将状态数据保留一段时间(例如一年)。这种行为是自愿的,取决于节点自身的配置,所以如果我们希望发送区块的矿工可靠,我们必须让它提供托管证明。

但是一致性层不知道哪些数据是有效的,哪些是无效的,这意味着访问新数据的Gas开销无法与访问旧数据的Gas开销区分开来,这意味着定价规则不能是每条指令,而是需要结合指令和数据状态,访问有效数据的Gas成本大于无效数据,如果区块中的交易都是访问失效数据的交易,那么见证数据可能会非常大。

因此,为避免上述弊端,必须在共识层面跟踪每个账户的状态,包括未使用的账户空间。这进一步说明实现“无状态与有状态到期”是一个复杂的权衡过程。

七、见证数据

无论“状态膨胀”问题的解决方案最终证明是成功的,必须解决的一个问题是确保使见证数据既易于生成又不会消耗无限带宽。

Alexey Akhunov一直致力于无状态的研究,他基于Ether做了一个分析,如果不对Ether协议做任何改动,见证数据的大小会在MB级别。目前以太坊按照gas极限12.5M计算,区块数据只有45KB左右,远大于区块数据。因此,无状态近几年的研究方向一直是以减少见证数据为主流。

八、EVMCode优化

根据Alexey Akhunov和turbo-geth团队的说法,假设一个基于当前以太坊数据模型的无状态客户端,合约代码将是网络(或见证数据)的第二大开销,并在可能优化后成为最大的存储结果(MPT->Binary)。因此,优化EVMCode似乎势在必行。

Sina Mahmoodi的解决方案是将整个合约代码拆分成几个基本区块,每笔交易只提供交易所使用的小区块和见证数据。

  • 可以理解为一条直线或顺序码,除入口外无分支进入,除出口外无分支出

  • 每个块都从索引0或jumpdest开始,无状态客户端可以安全地执行jumpdest解析

  • 对于每个块,执行要么到达终点,要么由于缺乏Gas而中止

最终,所有基本块都被添加到trie并计算出一个root。

可以看出为一笔交易执行的代码在root所在的trie上,这个root就是执行合约的root,这样就减少了无状态客户端交易中EVMCode的见证数据的大小。

EVMCode的这种优化同样适用于EVM2 (eWASM)。根据Sina Mahmoodi的研究,这种方法可以将EVMCode的大小减少40-60%。

数据存储结构优化

Merkle树的一个非常重要的特点是,可以在没有trie中所有数据的情况下,通过某条路径上所有依赖项的哈希值来验证Root的合法性,但是当我们去每个哈希值这样一条路径,我们发现与证明这个Root相关的路径(关联节点)太多,这使得提供见证数据非常困难,并且不能很好地压缩见证数据。

因此,提出了用二叉树替换Merkle的想法,对于最多一个分支被哈希替换的二叉树,可以更充分地切割Merkle树,这对于见证减少很有效。

假设一个区块中只有一个账户Acc1有交易,路径是3B(0011 1011),那么见证给出的二叉树需要7个分支和1个账户节点,共8*2=16个元素;十六进制树计算见证需要1个分支和1个账户节点,一共2*16=32个元素。

根据Mandrigin的实际测试,与十六进制树相比,见证使用二叉树节省了49%的大小,这一改进不如理论上的最佳情况那么显着,可能是由于主网区块中的真实数据分布,该提案有很大的优化空间。

二叉树减少了见证数据,但没有控制见证的大小,更严重的基于二叉树的重定价指令是非常困难的。

然后提出了一个新的KZG多项式承诺方案,KZG是Kate、Zaverucha和Goldberg对通用零知识证明方案PLONK实现的三重奏,其主要原理是通过一组椭圆曲线元素C= [f(s)]1将f(i)=vi提交到多项式f(x)并在任何点z处打开此承诺的能力,为验证者提供值y=f (z)和一个集合元素π=[(f(s)-y)/(sz)]1 ,这个证明值y的正确性可以通过配对方程来检验。

所谓的Verkle Trie是vector和Merkle的组合,使用一组向量v0,v1,…,vd-1作为输入,产生一个承诺C,C可以用这些值中的任何一个进行验证。例如,对于Merkle树,可以将其视为向量承诺,其中每个叶i的值可以通过对数16的哈希值来证明。

Dan认为Verkle Trie将是未来5年内解决通胀问题的最佳方案。

九、PlatON无状态机制实践

PlatON 期致力于“状态膨胀”问题,并率先在无状态概念中探索了一条新路径,将节点划分为“存档节点”和“普通节点”。

存档节点是保存所有状态数据的节点,而普通节点则是分阶段清理数据和事务日志的“历史状态”。在网络运行过程中,参与网络共识的节点不一定是存档节点,这意味着保证网络稳定运行的节点可以没有历史状态,从而不受“状态膨胀”的影响。

此外,PlatON上所有与经济相关的状态数据(例如 staking、委托等)都存储在名为snapshotdb的快照数据库中,每次创建新区块时,快照数据库都会计算出与当前区块对应的哈希值通过将所有历史数据和最新数据结合起来,最后将hash放到链上数据库(statedb)中,可以看作是上述再生方案的一种实践。

来源:PlatON

编译:Rachel

==

和2万人一起加入鸵鸟社群

添加QQ群:645991580

添加TG群:鸵鸟中文社区https://t.me/tuoniaox

本文经「原本」原创认证,作者 鸵鸟区块链 ,访问yuanben.io查询【 69SFCRF7 】获取授权信息。

免责声明:本文版权归原作者所有,不代表MyToken(www.mytokencap.com)观点和立场;如有关于内容、版权等问题,请与我们联系。