OG 是一个拥有智能合约的 DAG 高性能区块链。OG 底层采用了有向无环图(DAG)的账本构型,解决了现有块链区块链架构去中心化、安全、扩展性三角平衡问题。同时 OG 解决了 DAG 型区块链与智能合约的兼容性问题,能够确保在 DAG 结构下智能合约交易的有序性。
OG 具有如下特性:
效率:算力越大,效率越高。整个网络的交易吞吐量随着网络中全节点的加入而增加,交易的确认时间也随着全节点数量的增加而缩短,从而达到高扩展性。
公平:OG 中没有专门的节点负责网络状态共识,OG 网络中交易即共识,任何参与者既是网络使用者,又是维护者,地位平等。
安全:每一个交易的参与方都是前序交易的验证方并且被持续地以一种收敛的方式进行验证,要制造双花交易难度很大且成本非常高。
智能合约:OG 通过独有的共识排序机制解决了普通 DAG 账本无法有序运行智能合约的问题。OG 将无序的合约交易进行共识排序并上链,使得网络中每个节点上的虚拟机都有相同的运行结果和合约状态。
分片:OG 考虑到今后规模可能会快速增长,支持基于应用的分片,实现系统的高扩展性。
预言机:OG 通过有序的智能合约,支持线上账本与外部世界的沟通和数据调用。
DAG 形态
DAG,作为 OG 的底层协议和网络构型,同时满足了去中心化和高性能的双重需求。我们基于此,提出了能够满足高性能智能合约运行的构架。这章主要介绍 DAG 构架。
1. DAG
DAG,英文全称是 Directed Acyclic Graph,中文意为“有向无环图”。如果一个有向图无法从某个定点出发经过若干条边回到该点,这个有向图叫做有向无环图。
在 DAG 模型中,方框表示单元,线条表示关系,箭头表示从子单元到创世单元的方向,每个单元指向它的父单元。
与传统区块链不同,在 DAG 中,没有将交易封装成区块的概念,全网在同一时刻也不用对同一区块进行共识。DAG 中的每个单元为一笔交易,交易单元组成 DAG 网。由于大部分交易之间并没有很强的因果关系,因此可以异步并发写入交易,极大提高了并发量,同时将交易确认时间降低到最低,解决了传统区块链的扩展性问题,吞吐量可以达到超大规模,并且可以水平扩展。
2. Sequencer
在传统的 DAG 模型中,交易之间的异步发布和验证保证了整个系统的高吞吐量,但是同时也使得各交易间的时间顺序不可靠且不可验证,这使得 DAG 结构上使用智能合约成为难点。IOTA 尚未支持智能合约,Byteball 仅支持声明式非图灵完备合约。由于交易确认的不确定性、节点同步的不确定性、网络延迟的不确定性等原因,交易的插入顺序不能保证。对于普通交易来说,顺序的前后对最终结果不会有影响,因为 DAG 能保证整个网络交易结果的最终一致。但是对于智能合约,顺序的混乱会导致节点间的世界状态无法达成共识。
分布式系统中,实现智能合约的普遍做法便是维持节点间的状态一致。传统的单链区块链如以太坊,所有的针对智能合约的操作都会以交易的形式发布到链上并被矿工记录到区块中。出块节点决定了当前块中交易的顺序,工作量证明决定了不会有太多的分叉结果,即使分叉也能保证大部分节点的选择是正确的。各个节点在经过共识后能保证自己的区块链账本内容(交易)和其它节
点一致。在这个前提下,因为智能合约的操作顺序也被记录在账本上,所以各个节点在执行这些操作的时候会产生相同的结果,从而保证了合约状态的一致。
在 DAG 模型中,没有矿工统一打包交易这一步骤,每个节点对于网络的理解在每一时刻都有可能不同,这导致所有的交易呈现一个无序的状态。而无序的交易与状态一致性是互相矛盾的。这个矛盾点是制约 DAG 上智能合约实现的关键点。
为了解决无序操作造成的状态不一致问题,在继承了 DAG 中的交易单元与连线的模型后,我们创造性地提出了第二种单元的类型:Sequencer,这样我们的 OG 的组成元素即为:交易(Tx)单元、Sequencer 单元、有向连线(验证)。Sequencer 单元和 Tx 单元在 DAG 图中的作用是一样的,都可以去引用以及被引用,都需要被足够多的后继单元验证才能固定下来。其本质的区别在于提交人的不同以及承载的内容的不同。Sequencer 的主要作用是帮助 DAG 网络进行交易的共识排序。除此之外,下文也会提到 Sequencer 会作为一个公信单元,定期进行网络状态确定化的工作。
如上图所示,Sequencer 单元和普通的 Tx 单元在构建 DAG 的过程中的形态要求是一致的,都需要对之前的未经验证的单元(Tip1)进行验证。两者不同的是它们的内容:
Trunk Hash 和 Branch Hash 分别代表当前 Tx(或者 Sequencer)验证的两个Tip 的哈希。普通 Tx 的主要内容是转账双方的地址(From 和 To)以及转账的金额(Value)。Sequencer 不会有普通的交易转账信息,它的主要内容是合约相关的 Tx 的哈希值(TxSequencer 字段)。为了减少系统的冗余,TxSequencer 字段只会记录这些 Tx 的顺序和索引,不会记录 Tx 的完整内容。Sequencer 保证了这一批 Tx 的执行顺序。当任意节点收到 Sequencer 继而执行合约时,合约相关的Tx 执行顺序就依照 Sequencer 的内容来决定。
3. 状态确定化(Fanality)
Sequencer 除了确定智能合约交易的执行顺序外,还兼任定期将网络状态确定化的工作,防止网络被寄生链回滚。经过 Sequencer 验证的父单元,以及所有祖先单元的状态将被即刻确定,不能被推翻(即 Finality)。
Ivy
Ivy 是区块链中的账本,OG 中每一个节点的 Ivy 没有绝对的一致性,每个节点 Ivy 可能不太一样,但总体趋势是相同的,经 Sequencer 序列化后,也会确定下来一个主账本。因此 OG 的安全性也面临着艰巨的挑战,但 OG 改进了构造DAG 的要求和流程,杜绝 DAG 构型中存在的安全隐患。
1. 网络构建
OG 网络中一个单元需要验证前序的单元,应选择几个单元为最佳,本文给出建议是 2 个(见后证明)。这样才能被广播到网络上成为 DAG 网络的一部分。为了维护这个网络的安全、公平、高效,OG 综合考量了性能、安全、去中心化等因素,制定了如下前序单元的选择规则(A 系列):
1. 在满足以下规则的前提下,随机选择当前网络中未被确认的两个单元(Tip),无需考虑权重因素,虽然理论上允许,但不鼓励选择已被其它单元确认的单元。
2. 一个单元不能直接引用父单元直接或间接引用过的单元。
3. 一个地址如果创建发布超过一个单元,后发布的单元必须直接或间接地包含引用其之前发布的所有单元,形成这个地址的顺序单元系列。
Sequencer 同样需要遵守此条,即后一个 Sequencer 块必须直接或间接确认前一个Sequencer。
4. 如果一个地址发布的单元违反规则 A3,发布一个或多个没有顺序引用关系的单元或单元系列,都视为双花,无论是否存在实质性双花行为。
5. 在遵守规则 A3 的情况下,出现双花问题,根据顺序单元 Sequencer 确认时间,判定发布较早的有效,发布晚的无效。如果不遵守规则 A3,发布多个非顺序引用关系的单元或单元系列,根据最优顺序单元系列算法,只有一个单元或顺序单元系列有效,其余单元或顺序单元系列无效。
6. 如果一个地址的单元间接或直接引用两个或以上的同一人发送的没有顺序的单元,该单元无效,不论是否存在实质性双花行为。
A 系列规则主要防止恶意节点的双重支付攻击。任何有冲突的交易终将会被后继的收敛交易发现并孤立,最终作废。
如后文指出的,为了对自始至终只验证某几条交易的懒惰节点进行约束,我们制定额外的前序单元的选择规则(B 系列):
1. 长周期限制:新的单元不能验证古老的、已经被 N 个 Sequencer 块覆盖的单元。例如下图,令 N=2,则白色区域的新单元将无法以 Sequencer1 终结过的祖先单元作为父单元。这避免了懒惰节点永远选择某一个早就被验证的单元作为父单元的可能性。
2. 短周期限制:在长周期允许的范围内,为了避免懒惰节点选择某几个固定的存在于短周期内的已验证单元作为父单元、为了避免大量懒惰节点合谋作恶选取同一父节点,也为了对单个节点短时间内发送交易数量的限制,在选取父单元的过程中需要对父单元的哈希值进行限定,具体方法为:
a) 预先制定哈希函数 H string −> 64 bit heximal。
b) 节点选取父单元前需要进行一个难度不大的工作量证明,遍历出满足条件的 nonce,使得H tx,nonce ≤ a
c) 节点在广播单元前需要进行一个难度比 b)显著小的另一个工作量证明,遍历出满足条件的父单元 txA, txB,使得H H txA ,H txB ,nonce ≤ b
其中, a ≪ b. d) 如果无法从当前 Tip 池中选出满足条件的父单元 txA, txB,则该节点针对该笔交易,可选择:1,重新计算 b)中的另一个 nonce;2,选择更多或更少的父单元做验证;3,等待满足条件的父单元出现。
随机父单元选取方式
采用可变难度系数法则,定义难度系数X ,当交易被验证时,校验者调用难度公式,计算得到与之匹配的原始难度。
F 为总计算量,由父单元校验开销和本地挖矿开销组成。交易发送者可选择校验父单元个数 k,本地挖矿难度系数X与 k 存在反比例关系,如图 10。为了取 F 最小值,建议选取父单元校验个数为 2,如图 11,满足交易发送方性能最优原则,以及全网 TIP 收敛要求。
2. 随机选择原则
目前常见的 DAG 网络都依赖权重进行父单元的选择。如 IOTA 会根据马尔科夫蒙特卡洛演绎方法选择前序单元,使得选出某一个单元的概率分布与其路径上所有父单元权重造成的影响成正向关系。又例如 Byteball 设置中心化的Witness 来引导单元选择可信度高的前序单元。从效果上来看,任何企图引导单元、通过算法影响单元选择某些所谓的“主链单元”的策略都是低效且不必要的。事实上,这会造成大量单元采用雷同的策略进行交易选择,在交易量上升之后会造成大量交易由于不在偏好列表里,而无法被后续单元验证的情况。
以目前采用了马尔科夫蒙特卡洛演绎方法的 IOTA 网络为例,在 TPS 仅仅为11 的环境下,Tip 单元占比达到 39%,被至少一个单元验证过的单元比例仅为61%,其中最终被网络承认的单元比例仅为 18%.新生单元随大流,偏爱权重较高的主路径,跟随同一个节点后被后继单元的马尔科夫蒙特卡洛演绎方法淘汰,得不到任何确认的机会。
在 OG 中,单元在选择前序单元时不作任何路径上的假设和计算,完全随机选择在单元池中尚未被验证的新单元,只要该单元能够被合法链接(见下文描述)。完全随机的过程保证了每一笔在网络中的单元都能够有相同的几率被验证,而与区块所在位置无关。经过模拟,在同样的参数下,随机选择的策略保证了只要 TPS 规模不以几何级速度增长,该网络无论交易量大小,都能最终收敛。
智能合约
智能合约交易的运行是需要网络中所有节点共识顺序的,否则会造成执行结果的不统一。Sequencer 的到来使得 OG 网络中的所有节点对于智能合约交易的顺序有了共识。
1. Sequencer 的生成
和 一 般 的 DAG Tx 不 同 , 我 们 使 用 PoS (Proof-of-Stake) 共 识 生 成 每 个Sequencer。在系统中,有一部分节点在抵押了部分资产后会拥有 Senator 身份。拥有这个身份的节点将获得打包生成 Sequencer 的权利。Senator 的主要职责是将部分符合权重要求且与合约相关的 Tx 以权重为第一参考要素按顺序打包进Sequencer 中。在一轮 Sequencer 生成周期中同一时间只会有一个 Senator 进行打包工作,剩余的 Senator 会对新生成的 Sequencer 进行校验,只有通过其它Senator 校验的 Sequencer 才会被整个 DAG 网络承认。所有的 Sequencer 都会有先后的编号,Sequencer 与 Sequencer 之间始终保持着有序的状态。
2. 运行合约
在图 14 的场景中,节点需要执行合约时,首先它会从 DAG 中获取自己没执行过的最早(根据编号判断最早)的 Sequencer 也就是 Sequencer1。然后依据 Sequencer1 的 TxSequencer 字段保存的 Tx 哈希找到 DAG 中对应的 Tx 并逐条执行 Tx 的内容。最后将执行完的结果存储到自己本地的 DB 中。由于所有正常的节点在执行合约的时候都以 Sequencer1 中标注的 Tx 顺序执行,且所有人的Sequencer1 都是保证一致的,所以最后正常节点间的合约状态也会保持一致。执行完 Sequencer1 后下一轮执行 Sequencer2,如此往下循环下去。
安全
不管是块链架构的区块链还是基于 DAG 架构的区块链都必须解决双花、交易确定性、DOS 问题。本节将重点介绍 OG 如何通过自身结构上的安全机制免疫这些攻击 。
1. 针对 DAG 可能的攻击方式
目前影响 DAG 账本的安全性和高效性的尝试主要有以下几点:
1.1.寄生链双重支付
攻击者进行一笔双重支付,可以在原交易取得实质性结果(如货物交割,合约运行)后取消该交易,使交易对手方遭受损失,其具体步骤为:
● 攻击者在正常的网络中发送一笔交易并得到了足够的后继交易的确认
● 与此同时攻击者在一条不为人所知的本地链中发送双重支付交易
● 攻击者持续在本地链中发送大量交易,这些交易用于确认该双重支付交易,并且不确认正常网络上的原始交易。
● 这些交易既可以通过大量身份产生(女巫攻击),也可以不定期地确认正常网络上的交易(寄生在正常网络上的寄生链),从而达到增加自身权重、混淆视听的目的。
● 当攻击者认为自身的寄生链已经超过主链,从而使得大部分主链上的后继交易在面临双花选择时倾向于选择寄生链而非主链时,将这条寄生链公布于众。
● 一旦成功,主链上之前已经确认过的交易,连同它前后的交易都面临被抛弃的风险。
OG 的设计杜绝了寄生链存在的可能性。寄生链成功的关键在于攻击者能够以更快的速度在不为人知的本地 DAG 网络上构建出比主网权重更大的 DAG 分支。该行为决定了这些私有交易不能被广播,否则网络上任何一个单元都有可能在第一时间发现该双花交易而将之隔离。
OG 引入的 Sequencer,同时也是交易终结性的确定者。被 Sequencer 直接或间接验证的交易直接进入终结状态。寄生链由于不能广播自己,因此无法被Sequencer 看到,也会远比正常单元晚进入网络。正如规则 B1 所述,任何一个诚实节点在验证既往交易的时候,都不会用这些突如其来没有被 Sequencer 终结过的交易去覆盖已经被终结过的原始交易。Sequencer 的存在加速了交易的确认速度,同时防止了恶意攻击企图推翻较长历史的尝试。
1.2.懒惰节点
一笔新的交易需要验证之前未被验证的交易。但由于网络延迟的因素存在,无法避免一笔过往的交易同时被多笔交易验证。一般而言,新的交易应当随机选择在交易池中未被验证的交易,从而使得交易池中的交易能够被快速消耗。
然而一个懒惰节点会倾向于验证某一个固定的早已被验证的远古交易(例如一个在核心路径上的老交易)。这样对于该懒惰节点而言,只需验证一次,就可以广播无数交易,并且其它诚实节点同样会确认该笔交易。这种懒惰的行为虽然不会对整个网络的安全性造成影响,但是它们提高自己效率的代价是降低整个网络的性能。因此在 DAG 账本中,无论该类节点是出于何种目的(代码实现错误、纯粹利己节点、寄生链节点等),均需要对这种行为进行约束或惩罚。
OG 通过独特的父节点选择算法保证了单个节点不可能每次都选择固定的一个或几个父节点,也保证了多个节点无法串通选择某一个或几个父节点。正如B2 所述,单元需要先遍历出一个与交易信息相关的本地 nonce,使得该单元Hash 小于某个难度值 a。这个过程(PoW1)需要被设计成占用 90%以上的挖矿时间。一旦 nonce 确立,单元需要将该 nonce 与潜在的两个父单元的 Hash 进行合并,计算 Hash,使得该挂钩 Hash 小于某个难度值 b。这个过程(PoW2)需要被设计成占用 10%不到的挖矿时间。
我们的目的在于让节点在每次选择未确认单元的时候都倾向于选择不同的单元而非同一个。影响最终单元有效性的因素有两个:父单元的 Hash 和本地的nonce。之所以设计 PoW1 难度远大于 PoW2,是因为我们要让节点在进行 PoW遍历的时候,更换父单元的难度要远远小于更换 nonce 的难度。这样如果一个懒惰节点执意要跟随某一个固定交易,那么它无法享受算法给他带来的优惠(换父单元,PoW2),必须每次都要换 nonce,而换 nonce(需要进行 PoW1)又是一件非常困难的事情。
父节点选择算法同样限制了多个节点合谋跟随同一个交易的企图,原理与限制单个节点跟随同一个交易一致。
1.3.DoS
作为一个全节点,既是网络的使用者又是网络的维护者,因此发送交易无需手续费。然而无手续费可能会诱使恶意节点发送大量微小单元进行对网络的“合法”的或“非法”的 DoS。
对于合法的 DoS,其交易格式正确,则 PoW 必须要能够通过验证,而计算PoW 对于一笔正常交易来说时间微不足道,但要形成足以影响 DAG 网络的量级的 DoS,需要攻击方付出大量的算力成本。
对于非法的 DoS,其交易格式不正确,则收到该交易的节点不会中继这笔交易。攻击者最多影响该单个节点,而几乎无法影响整个 OG 网络,也无法通过攻击 OG 网络的一部分而对整个 OG 网络进行有效攻击。
2. 安全的虚拟机
作为以太坊最核心的功能之一,智能合约及其语言 Solidity 在近年来得到了广泛的应用。以太坊虚拟机 EVM 及智能合约虽然满足了图灵完备的功能要求,但是在安全性方面已经被证实存在较多缺陷,这对于一个运行着经济模型的区块链系统而言是有非常大风险的。例如,基于以太坊发行的虚拟币 SMT、EDU、BEC 均由于未使用 SafeMath,导致在代币数量计算过程中整数溢出,导致货币超额增发;又例如,Fomo3D 所采用的随机数算法在同一区块中能够被复现,同一区块里的其它交易能够预测该随机数,从而导致抽奖算法存在不公,间接导致了该团队其他项目的失败。对智能合约的安全性审查过于复杂,需要考虑多方面因素,严重影响了其公开透明的特性,使得普通用户难以验证该合约是否存在漏洞。
与其让开发者在每个合约中都对合约的安全性反复斟酌,OG 从源头上,即智能合约语法和虚拟机本身去解决安全问题。
数值安全:传统的 EVM 对于溢出采取的是容忍的态度,而 OG 的虚拟机则完全不允许溢出,从根源上避免了大量非预期的行为。
类型安全:EVM 对于代币的实现与普通整数无异,导致货币可能被简单增发。而 OG 原生提供 Coin 类型,对于代币的操作都有一套独立的、区分于普通数值计算的方式。
权限安全:从语言层面上强制智能合约编写者显式指定所有函数的权限要求,避免了由于疏忽导致的高危函数被越权调用的问题。
OG 的智能合约语言和虚拟机旨在对目前常见的 Solidity 漏洞进行根源上的避免,令智能合约不再危险。
总结
OG 提出一种基于 DAG 通用区块链架构,主要解决现有区块链中去中心化、扩展性、安全三者平衡难题及 DAG 如何结合智能合约。我们很高兴看到我们所做的探索及一些成果,但其中有些问题本文中还没给出很好的解决,如安全性,强一致性及最终性。