每晚八点,我们在社区分享知识,等你。
NervosFans 微信公号:Nervosfans
入群请加乐乐微信:sensus113 美果大冰微信:xj73226
备注入群,谢谢!
假设状态转换可以用数学形式表达成STF(S, B) -> S’,其中S、S’代表状态,B代表区块(或者是T,代表交易),那么STF就是状态转换函数。
理论上,很多长成这个样子的协议,都能通过同种协议变形进行变更的。
转换过程如下:
S变成S的状态根,好比含S的32字节Merkle Patricia树根哈希
B变成(B,W),其中W代表‘证人’,即证明执行B可访问的所有数据的值的一组Merkle分支
STF变成STF’,以状态根以及区块+证人(数据)做输入,然后在执行区块需要读取账户信息、存储密钥或其他状态数据时,使用证人做‘数据库’数据库(若证人不包含请求数据片段,则退出并提示错误),最后输出新状态根
也就是说全节点只存储状树根,打包区块与Merkle分支(‘证人’)是矿工的事;然后由全节点下载并验证这些大(带证人数据的)区块。所以无状态全节点与常规全节点是完全可以在同一个网络中和平共处的;设置个翻译(转换)节点,为区块B附上验证其所需的证人数据,然后在另个都是无状态节点网络协议中广播这个(B,W);矿工在该无状态网络上挖到区块后,把附带的证人数据去掉,然后重新在常规网络上进行广播。
在现有协议上实现证人最简单的办法是把它当成个RLP编码的对象列表,可被客户端解析为{sha3(x): x}键值对;这个键值对可被用作‘数据库’直接插入到当前的以太坊实现中。
上述概念应用到当前以太坊中,有这么个问题:矿工还得是储存状态的全节点。想象这么个系统,说交易发送人需要存储全部状态特里结构,然后矿工还是无状态的,问题是以太坊的状态存储访问是动态的。举个例子,说有个合约长这样getcodesize(sha3(sha3(...sha3(x)...)) % 2**160),里边有N(比如N=109)次sha3运算。也就是说不消耗N次计算的gas,就无法访问账户代码。那么,交易发送人可以发起一笔包含若干账户证人数据的交易,然后进行大量计算,但最终还是在访问一个自己没有证人数据的账户。这个问题跟DAO软分叉漏洞是一样的。
解决问题的办法可以是规定交易包含自己可访问账户的静态列表;类似EIP648,但是更为严格,原因是静态列表属于精确枚举,EIP648的话属于提供范围那种。然后,就出现了另个问题:交易在网络中广播完毕时,状态访问的账户信息以及提供证人数据的(正确)Merkle分支可能就与交易被创建时的(正确)数据不一样了。为应对此问题,可将证人数据置于交易中的签名数据‘之外’,然后允许打包交易的矿工打包交易钱按需调整证人数据。若全体矿工默认保留一定时间内(比方说过去24小时)创建的全部新状态树节点,说明矿工掌握更新过去24个小时内发布交易的Merkle分支所需的全部信息。
该设计的优点如下:
1. 矿工及全节点无需存储任何状态,那么“快速同步”速度会更快(可能几秒)。
2. 由状态存储经济模型引发的租赁设计
(见:https://github.com/ethereum/EIPs/issues/35、
https://github.com/ethereum/EIPs/issues/87、
https://github.com/ethereum/EIPs/issues/88)
甚至是当前复杂的SSTORE成本/退款方案等问题都消失了,那么区块链经济模型就能完全专注于定价带宽与计算,这就简单多了。
3. 对于矿工与全来说,磁盘IO不再是问题。磁盘IO一直以来都是造成以太坊DoS漏洞的主要原因,时至今日,仍盘踞最简单可用的DoS向量。
4. 要求交易指定账户列表这波操作以外的带来了高度可并行;可以理解成是EIP 648的增压版本。
5. 即使于存储状态的客户端来讲,帐户列表允许客户端从磁盘预取存储数据(并行应该是),从而大大提升客户端抵御DoS攻击的能力。
6. 分片的区块链中,在各个片间频繁的移动(reshuffle)客户端也提升了安全性;BFT模型中,客户端变动越快,分片免受攻击的适应性越。不过,状态存储客户端模型中,被移动客户端需要下载新片的全部状态。无状态客户端中,这个成本降为零,允许客户端在自己产生的区块间来回移动。
不过,无状态客户端概念有个问题:状态由谁存储?以太坊的主要优势之一在于平台的易用性,用户不用关注存储私有状态这种细节。那么,想要无状态客户端运行顺畅,需要借鉴下以太坊的用户体验。以下是有关how to的一些(组合)想法:
1. 默认被创建或触及的新状态特里对象由所有全节点存储3个月。数据约2.5GB,有点像是网络自愿提供的“福利存储”。其实提供这种层次的服务完全可以是自愿行为,原因当前轻客户端基础设施本身就是利他主义的体现。3个月后,客户端可以随机丢弃数据,好比12个月之前触及的状态特里对象仍由25%的节点存储,60个月前触及的对象仍由5%的节点存储。客户端可尝试用常规轻客户端协议请求这些对象。
2. 想要特定数据片段的可用性更久,可通过状态通道支付实现。客户端可以与收费的存档节点建立通道,进行有条件支付,比如说,以‘我拿出0.0001美元,默认永远不会拿回这笔资金。若后来你能提供带哈希值H的对象,我同意后,这0.0001美元就归你’。这相当于承诺未来愿意以解锁资金的方式换取某对象(数据),而存档节点可以参与非常多的这种(有条件支付),坐等各种数据请求然后收各种款。
3. 我们还希望dapp开发者能够让自己的用户在浏览器本地存储中随机存储些与自己dapp相关的存储密钥。这个完全可以在web3 API中轻松实现的。
实践中,引入分片后,为服务网路,预计‘啥都永久保存’的存档节点数量会维持在一个比较高的水平,直到总状态大小超过~1-10TB,届时可能也就不需要存档节点了
相关讨论:
· https://github.com/ethereum/sharding/blob/develop/docs/account_redesign_eip.md
· https://github.com/ethereum/EIPs/issues/726
https://ethresear.ch/t/the-stateless-client-concept/172
网友评论