数字产权项目帮助中心
DPR数字产权平台帮助文档

DPR Chain 详细设计

...

来自于:Song2

最后更新时间: 2 年多前

一、共识

1. 共识简介
DPR Chain 所采用的共识协议结合了实用拜占庭容错算法(PBFT)和权益证明算法(POS),能容忍1/3(不包含)的故障节点(指1/3的 Power,而非1/3的共识节点 Validator),且不会分叉。每个共识节点 Validator 都配置有一个共识权重 Power,通过共识权重 Power 来确定下一高度的出块节点 Proposer,并最终由 Proposer 来打包交易并出块。
共识算法给每个区块赋予一个增量高度 height,在某一高度中只存在一个有效的区块,区块链从高度为0的创世纪块开始,由一个共识节点集合 ValidatorSet 投票产生下一个区块。在投票产生某一高度的区块的过程中,在正式提交 commit 某一高度的区块之前,至少需要经过一轮投票来达成共识。每一轮都会产生一个与上一轮不同的提议者 proposer,该提议者 proposer 在当轮以广播的形式提出一个提议 proposal,提议 proposal 经过验证者 Validator的集体投票,来决定是否最终提交该区块或者进入下一轮。在提议的区块真正被提交 commit 之前,验证者们需要进行两轮投票(pre-vote 和 pre-commit), 通过一个简单的锁机制用来阻止少于总数1/3的拜占庭节点攻击。为了应对单个拜占庭故障节点,DPR Chain 网络至少需要包括4个共识节点。每个共识节点拥有一对非对称密钥,其中私钥用来进行数字签名,公钥用来标识自己的身份ID。共识节点们从公共的初始状态开始,初始状态包含了一份共识节点列表。所有的提议和投票都需要各自的私钥签名,便于其他验证者进行公钥验证。下面这张图是共识算法的状态转换图:
共识算法的状态转换周期为:NewHeight -> Propose -> Prevote -> Precommit -> Commit 五个阶段。上述每个状态都被称为一个 Step,首尾的 NewHeight 和 Commit 这两个 Steps 被称为特殊的 Step,代表一个新区块的开始和提交。每一轮开始期间,存在一个用来计时的本地同步时钟,如果验证者在TimeoutPropose时间内没有收到提议,验证者将参与投票来决定是否跳过当前提交者。TimeoutPropose会随着轮数的增加而增加。每轮收到提议以后,进入完全异步模式。之后验证者的每一个网络决定需要得到2/3以上验证者的同意。这样降低了对同步时钟的依赖或者网络的延迟。中间三个 Steps 则被称为一轮 Round,是共识算法的核心原理所在。一个块的最终提交Commit可能需要多个 Round 过程,这是因为有许多原因可能会导致当前 Round 不成功(比如出块节点 Offline,提出的块是无效块,收到的 Prevote 或者 Precommit 票数不够2/3等)。
共识算法可以大致分为以下部分:
  • 提议(Proposal):在每一轮(Round)中,新区块的提议者必须是有效的,并且广播给其他验证者。如果在一定时间内没有收到当轮提议(proposal),当前提议者将被后面的提议者接替。
  • 投票(Vote):两阶段的投票基于优化的拜占庭容错。它们分别被称作预投票(pre-vote)和预提交(pre-commit)。对于同一个区块同一轮如果存在超过2/3的预提交(pre-commit)则对应产生一个提交(commit)。
  • 锁(Lock):在拜占庭节点数少于节点总数的1/3的情况下,锁机制可以确保没有两个验证者在同一高度提交(commit)了两个不同的区块。锁机制确保了在当前高度验证者的下一轮预投票或者预提交依赖于这一轮的预投票或者预提交。
2. 提议
每轮Round开始于一个提议(proposal),提议者从内存池(Mempool)选取一批交易进而构成了一个区块,该区块随后被嵌套在ProposalMsg中,最后提议者广播ProposalMsg。
提议者通过一个简单并且相对固定的的Roubd Robin算法轮流坐庄,所以每一轮只有一个有效且被所有验证者公认的提议者。如果验证者收到了之前更低轮次的提议或者提议来自于非法的提议者,该提议将被拒绝。Round Robin算法基于validator的power,每轮选择power最大的validator选为proposer,然后将proposer的power减去所有其他validators的初始power总和,未选中的validtors各自将自己的power值累加上自己初始的power值。
提议者的轮流坐庄对于拜占庭容错是必要的。比如,对于raft算法,如果选举出来的leader是拜占庭,并且leader与其他节点网络连接状态良好,该leader可以完全控制整个网络,网络节点的安全和正常运转将无从得到保障。DPR Chain共识算法通过投票和锁的机制确保了系统的安全性。如果一个提议者在限定时间内没有处理任何交易,排在其后的提议者将会接替他。
3. 投票
一旦验证者从网络中收到了一份完整的提议(proposal ),他对该提议进行预投票(pre-vote)签名,并且广播到网络中。如果验证者在ProposalTimeout时间内没有接收到一个有效的提议,其对该提议的预投票为空(nil)。
在存在拜占庭节点的异步环境中,单阶投票,即每个验证者对每个提议只投一次,不能足以确保整个系统的安全。本质上,因为验证者可能做出一些不诚实的行为,并且消息的到达时间没有任何保障,一个不诚实的验证者可以与其他验证者进行协作来提交(commit)一个区块,然而其他没有看到这个提交区块的验证者进入了新的一轮,并提交(commit)了一个不同的区块。
一个单阶的投票允许验证者互相沟通他们知道的关于该提议的信息。但是为了容忍拜占庭故障,他们也需要互相告诉对方他们自己了解到的其他验证者声称了解到的关于该提交的信息。换句话说,二阶段提交确保了足够的验证者见证了第一阶段的结果。
对于某个区块的非空预投票是为网络提交(commit)区块已做好准备的投票。空预投票是为网络直接进入下一轮的投票。在理想的一轮中,超过2/3的验证者为该提议进行了预投票。在任意一轮中,区块具有的超过2/3的预投票被称作一个波尔卡(polka)。超过2/3的空预投票成为空波尔卡(nil-polka)。
当一个验证者收到了一个波尔卡(polka),他接受到了一个信号,即网络准备提交该区块,作为一个验证者签名并且广播预提交(pre-commit)的背书。有时,由于网络的不同时性,验证者可能没有收到对应的波尔卡或者波尔卡根本就不存在。在这种情况下,验证者没有对应的波尔卡为这个预提交背书,此时预提交为空。也就是说,在没有收到波尔卡背书的情况下,签名一个预提交被看作是一个恶意行为。
预提交(pre-commit)是关于提交(commit)一个块的投票。空预提交则投票进入到下一轮。如果验证者收到2/3以上验证者的预提交,则其在本地提交该块,计算结果状态,并移动到下一高度的第0轮。如果验证者接收到超过2/3的空预提交,则投票进入下一轮。
4. 锁
多轮投票的安全问题是棘手的,必须避免同一高度不同轮数分别提交两个不同区块的情形。在DPR Chain中,这个问题可以通过锁机制得到解决。锁机制的大致定位在波尔卡附近。本质上,预提交必须有一个波尔卡为其背书,验证者被锁定在其最近预提交(pre-commit)的区块上。
锁定规则:
  • 预投票锁(Prevote-the-Lock):验证者只能预投票(pre-vote)他们被锁定的区块。这样就阻止验证者在上一轮中预提交(pre-commit)一个区块,之后又预投票了下一轮的另一个区块。
  • 波尔卡解锁(Unlock-on-Polka ):验证者只有在看到更高一轮(相对于其当前被锁定区块的轮数)的波尔卡之后才能释放该锁。这样就允许验证者解锁,如果他们预提交了某个区块,但是这个区块网络的剩余节点不想提交,这样就保护了整个网络的运转,并且这样做并没有损害网络安全性。
简单来说,验证者可以被看作锁在任意高度-1轮的nil-block上,所以波尔卡解锁意味着验证者不能预提交一个新高度的区块直到他们看见一个波尔卡。
这些规则可以以例子的形式被更直观的理解。考虑4个验证者,A,B,C,D,假设有一个第R轮关于blockX的提议。现在假设blockX已经有一个波尔卡,但是A看不见它,预提交(pre-commit)为空,然而其他人对blockX进行了预提交。进一步假设只有D看见了所有的预提交,然而其他人并没有看见D的预提交(他们只看见他们的预提交和A的空预提交)。D现在将要提交(commit)这个区块,然而其他人进入到R+1轮。由于任何验证者都可能是新的提议者,如果他们提议并投票了一个新的区块blockY,他们可能提交这个区块。可是D已经提交了bockX,因此损害了系统的安全性。注意,这里并没有任何拜占庭行为,仅仅是不同时性。
锁定解决了这个问题通过强迫验证者粘附在他们预提交(pre-commit)的区块上,因为其他的验证者可能居于这个预提交进行了提交(如上例中的D)。本质上,在任何一个节点一旦存在超过2/3预提交(pre-commit),整个网络被锁定在这个区块上,也就是说在下一轮中无法产生一个不同块的波尔卡。这是预投票锁的直接动机。
当然这里必须有相应的解锁方式。假设在某一轮中,A和B预提交(pre-commit)了blockX,与此同时C和D的预提交为空。因此所有的验证者进入到下一轮,预提议(pre-vote)blockY。假设A是拜占庭,为blockY也进行了预投票(不考虑其被锁在blockX上),导致了一个波尔卡。假设B并没有看见这个波尔卡,预提交为空,此时A下线,C,D预提交bolckY。他们进入到下一轮,但是B仍然被锁定在blockX上,C和D被锁定在blockY上。这时因为A下线了,他们将永远得不到一个波尔卡。因此即使在拜占庭节点少于1/3的情况下,这里网络的正常运转仍然受到了影响。
解锁的条件是1个波尔卡。一旦B看见了blockY的波尔卡(用来为C和D的关于blockY的预提交背书),他应当能够解锁并预提交(pre-commit)blockY。这是波尔卡解锁的动机,其允许验证者在看见更高轮数波尔卡的时候解锁并且提交对应的新区块。

二、地址

在DPR Chain中有3类地址:节点地址、用户地址、智能合约地址。
节点地址和用户地址采用 secp256k1椭圆曲线算法生成公私钥对,其中节点地址是公钥进行sha256哈希后再进行RIPEMD160算法得到,用户地址则是在节点地址的算法基础上,再通过Bech32算法加上“dpr”地址前缀而得到。节点地址可以转换成用户地址进行资产转移,因为节点地址和用户地址底层的公私钥算法是采用的相同secp256k1椭圆曲线算法。
智能合约地址是通过合约创建者的地址拼接上该地址的nonce,对其进行sha256哈希后进行RIPEMD160算法,再通过Bech32算法加上“dpr”地址前缀得到。该地址不包含私钥,不能通过私钥签名的方式转移该地址上的资产。
地址在存储层均采用16进制编码的byte数组表示,算法同节点地址生成算法。

三、账户

1. 账户模型
DPR Chain账户模型采用余额模型,余额代表了账户中的Gas数量。DPR Chain的账户分为外部账户和合约账户。
外部账户是具有私钥的账户,此类账户谁有私钥,谁就有对该账户的控制权,进而主动发起交易请求。
合约账户是没有私钥的账户,账户地址通过交易发起者地址及其nonce生成,不含公私钥对,即不能通过公私钥对来控制账户。该账户不能主动发起交易,只能接收到外部账户调用后才能发起交易或者调用其他合约账户。
2. 账户结构
DPR Chain的账户结构主要包含3个属性:Address、Nonce、CodeHash。
  • Address是该账户对应的地址
  • Nonce是该账户的地址生成次数,用于生成合约地址及生成DP的标识ID。每生成一次后该数字累加1。
  • CodeHash只有当账户为合约账户时才有值,是合约源代码的sha256后的值。

四、区块

区块链是一个个包含了一批交易、区块描述信息的区块通过链接到之前的区块而形成的链式结构,在DPR Chain中这种链式结构是通过两种形式组成的:前区块散列以及一组使得前区块得以commint的precommits数据(即“LastCommit”)。那么一个区块至少包含三个部分:区块头、交易列表以及LastCommit,在DPR Chain中如果发现Validator有恶意行为,其他validator可以以交易的形式发布违规Evidence,DPR Chain将踢出作恶节点,为Validator清理门户,因此,区块还将包含Evidence数据。区块结构如下图:
区块是从一个共识节点发出的,并且区块大小不确定,有可能会非常大,对于块提议节点来说把数据上传到所有其他节点的方式压力过大,如果把区块分成若干块后再广播出去会快很多。一个常用来保证数据被安全广播的方法,就是利用Merkle树,此方法也被各种P2P协议所采用,具体方法就是允许每一段数据伴随一个简短的证明(原数据的对数级大小),用来证明该片段是整体的一部分。为了使用这种方法,根据区块大小和验证者的数量,区块被序列化并分割成适当大小的块(chunks),块(chunks)被散列成Merkle树。被签名的提议(proposals)不再包含整个区块,而是只包含Merkle的根哈希(root hash),允许网络通过协作来广播被分割后的块(chunks)。节点每次收到块(chunks)时都会通知它的对等节点,来避免把同一个块向一个节点传输多次,以此来节省带宽。一旦节点接收到所有块,就对块进行反序列化和验证,以确保它正确地指向前一个块,并且其各种校验和(用Merkle树实现)是正确的。虽然先前假定验证者在接收到提案(包括块)之前不预先投票,但是通过允许验证者在收到提案之后,在接收到完整的块数据之前进行投票,可以提升性能。这意味着预先投票到最后证明是无效的块也是可以的。不管怎么样,对一个无效区块进行预提交(pre-commit)被认为是拜占庭行为。
当一个节点链接一个新的对等节点时,这个对等节点需要把它当前区块高度发送给对方。节点并行的从所有比自己高度高的对等节点中循序的请求区块,并下载区块加入到自己的区块池(block pool)。另一个协程不断尝试从池中删除块并通过验证和执行将它们添加到区块链中,一次两个块。必须每次同时处理两个区块,因为一个区块的提交确认被包含在下一个区块的LastCommit字段中。节点持续的查询它所有对等节点的当前高度,同时不断的并行请求区块,直到同步到其所有对等节点的最高高度。一旦同步到最高高度就会停止请求区块,然后以一种相对较慢的方式来同步区块,即节点在处理下一个块之前,会等待接受到所有的信息来确认当下的一个块。

五、交易

1. 交易结构
DPR Chain的交易结构包含以下信息:
  • Message,是交易的具体内容,是protobuf Any类型,不同类型的交易最大的区别就是Message的结构不同。
  • TimeoutHeight,代表该笔交易执行失效的最高区块高度(TimeoutHeight块仍可以打包该交易),当区块链到达该高度而该交易仍未执行时,以后的区块也不会再成功执行该笔交易。
  • Memo,是用户发起该笔交易的备注,便于用户处理自己特有的业务逻辑。
  • GasPrice,指该笔交易的Gas手续费价格,在DPR Chain中该字段为保留字段,用户无需手动设置,即该值为固定值。
  • GasLimit,代表该笔交易最大可花费的Gas数量,当交易所需花费的Gas数量大于该值时,交易会执行失败。
2. 交易流程
DPR Chain的交易分为:发起、广播、打包与执行、验证与执行几个阶段。用户在本地构建交易并签名,然后将交易广播到区块链网络,共识节点收到交易后进行基础验证,验证通过则将该交易放入到节点的交易池中。出块接口将交易池中的交易打包并执行,其他节点收到区块后进行共识验证,如果共识验证通过则执行交易。每笔交易均需要支付Gas手续费,Gas手续费费用由交易发起人支出,并由出块节点收取。

六、节点

1. 节点类型
DPR Chain中的节点可分为以下类型:
1)全节点
节点是参与区块链网络但不参与共识出块的节点,其可用于存储区块链的整个状态,为区块链网络提供服务,帮助其他节点达成共识,帮助其他节点赶上当前区块等。
2)验证节点
验证节点是参与区块链网络安全的节点,具有共识出块的权力。每个验证节点都配置有共识权重power,共识时通过power选举出当前块的出块者proposer,并由proposer打包交易并出块。
3)种子节点
种子节点是其他节点启动时可以连接的节点列表,在启动节点时,您必须提供至少一个种子节点才能连接到区块链网络。
2. 验证节点管理
DPR Chain设计了一个链Admin账户,该账户具有验证节点管理的权限,可以通过发送交易的形式来新增验证节点、删除验证节点、修改验证节点的共识权重power。

七、P2P

P2P网络协议借鉴了比特币的对等发现协议,即采用了BTCD的P2P地址簿(Address Book)机制。当连接建立后,新节点将自身的Address信息(包含IP、Port、ID等)发送给相邻节点,相邻节点接收到信息后加入到自己的地址薄,再将此条Address信息,转播给它的相邻节点。

八、存储

DPR Chain的物理存储引擎使用的是LevelDB,其存储着区块链的状态数据及交易历史。其主要包含以下数据文件:
  1. application.db:应用数据
  2. blockstore.db:区块数据
  3. cs.wal:预写日志数据
  4. evidence.db:验证节点作恶证明数据
  5. peerstore.db:节点数据
  6. state.db:区块链状态数据
  7. tx_index.db:交易索引数据
区块数据存储流程如下:
交易由最终用户构建签名后提交到区块链,链上校验通过后放入交易池,交易池中的交易由出块节点取出并打包进区块,并把交易数据和最终状态持久化到LevelDB。

九、Gas

1. Gas 简介
DPR Chain中的Gas是区块链的能量,交易上链需要收取一定的Gas手续费,此部分的手续费最终由打包此笔交易的出块节点收取。Gas设计为整数类型,消除小数运算带来的精度问题。Gas有一个开关可以控制用户是否可以自由转账,同时Gas还有一个白名单地址列表,白名单中的地址可以在Gas自由转账开关关闭时仍可以自由转账。
下面是与Gas相关的具体操作:
  1. 创世文件中配置有Gas的元数据信息。
  2. Admin可以通过交易的形式修改部分元数据信息:转账开关和白名单。
  3. Admin可以通过交易的形式修改交易的基础Gas和每个字节对应的Gas单价。
  4. 打包交易时收取交易发起人的Gas,并由出块节点收取。
  5. Gas转账及Gas授权转账功能。
  6. 查询账户的Gas余额。
2. Gas经济模型
Gas作为DPR Chain的能量,其总量是有限的。每笔上链的交易都需要花费一定的Gas,普通交易消耗的Gas数量与交易大小有关,当交易大小小于交易基础值(固定值)时收取基础Gas费(固定),当交易大小超过了交易基础值时,在基础Gas费的基础上加收超过的字节数乘以固定价格计算出的Gas费用。
3. Gas手续费收取规则

十、DP

1. DP数据结构
DP是一类资产的数字化,其包含的属性有:
  • DpId,DP的标识ID
  • Creator,DP的创建者地址
  • Owner,DP的拥有者地址
  • DpType,DP的类型
  • Name,DP的名称
  • DpHash,DP的内容hash
  • Url,DP的URL
  • Extend,DP扩展信息
  • ProtocolType,DP的协议信息,目前包含DPR721
  • Symbol,DP的代码
  • TotalSupply,发行总数量
  • TransferStatus,交易状态
2. DP创建
DP由Creator创建,Creator在创建时可以指定其他地址作为该DP的拥有者Owner。创建DP时除了不需要提供DpId外,其他字段需要用户在创建时提供。DpId由链上生成,其生成规则是将Creator地址连接上Creator地址的nonce进行sha256后进行RIPEMD160算法,再通过Bech32算法加上“dpr”地址前缀得到,其生成算法同智能合约地址生成算法。
3. DP授权铸造
DPR Chain中的DPR一般情况下由Owner铸造,但是Owner可以将铸造权授予其他地址,这样其他地址也可以进行该DP的DPR的铸造。在创建DP的时候可以指定可以铸造该DP的授权白名单,也可以通过授权铸造交易来添加该DP的授权铸造白名单。

十一、DPR721

1. DPR721数据结构
DPR721是数字产权的一种表现形式,其包含如下属性:
  • DpId,DP的标识ID
  • DprId,DPR的标识ID,由链根据DPR信息生成
  • BuesinessNo,DPR的业务编号
  • DprOwner,DPR的拥有者地址
  • RightType,DPR权利类型
  • ExpireTime,DPR过期时间
  • Status,DPR状态:0-销毁、1-正常
2. DPR721铸造
在DPR Chain中DPR的铸造交易只能由DP的拥有者或者已经授权的具有铸造权限的授权白名单地址发起。DPR721铸造需要传入From、DpId、DprOwner、BuesinessNo、ExpireTime、RightType字段,然后DPR Chain根据传入的Dpid、BuesinessNo、ExpireTime、RightType4个字段计算出DprId,计算出的DprId会存证以下3种情况:
  •  DprId链上不存在,则直接铸造DPR,并将Status设置为1。
  • DprId链上已存在且Status=1,则该笔交易上链失败。
  • DprId链上已存在且Status=0,则将该DPR的DprOwner设置成交易中的DprOwner同时将Status设置为1,即DPR721销毁后可以重新铸造,且重新铸造时可以修改原有的拥有者地址。
3. DPR721转移
DPR721可以在用户之间自由转移,DPR721拥有者from通过发起DPR721转移交易将DPR721转移给接收者to,从而将DPR721的控制权转移给to地址。DPR721转移交易的Message包含如下字段:
  • From,交易发起者,From地址必须是DPR721拥有者地址。
  • To,DPR721接收者地址
  • DprId,要转移的DPR标识ID
4. DPR721销毁
在DPR Chain中DP的拥有者Owner拥有DPR721的销毁权限,可以将用户的DPR721进行销毁。销毁后链上仍有该DPR721记录,但是该DPR721的Status会设置为0(已销毁)。当该DPR721需要重新铸造时,DP的拥有者Owner或者已经被授权可铸造的白名单地址可以再次铸造该DPR721,重新铸造是将修改该DPR721的Status为1(正常),且重新铸造是可以重新设置DPR721的拥有者Owner地址。

十二、智能合约

智能合约并非现实中常见的合同,而是存在区块链上的可以被触发执行的一段程序代码,这些代码实现了某种预定的规则,是存在于区块链执行环境中的“自治代理”。DPR Chain中的智能合约兼容以太坊智能合约虚拟机EVM,智能合约语言采用Solidity。DPR Chain中的智能合约设计如下:
  • 任何人都可以在DPR Chain上开发智能合约,这些智能合约的代码存储于DPR Chain的合约账户中。
  • DPR Chain的智能合约程序运行在DPR Chain虚拟机上(兼容EVM虚拟机)。
  • 合约账户不能主动运行智能合约,要运行一个智能合约,必须由外部账户发起交易,从而启动合约账户中的代码来执行。
  • DPR Chain中运行智能合约需要消耗Gas。

十三、权限管理

DPR Chain的权限管理主要设计思想为在区块链系统中增加了Admin角色,Admin角色对区块链网络具有比较高的控制权,当然Admin自己可以将权限移交给其他账户。以下是Admin控制的相关业务:
  • Admin可以控制共识节点的加入、踢出、修改共识节点的共识权重。
  • Admin可以修改Gas的转账开关
  • Admin可以修改Gas转账白名单

十四、区块链接口

DPR Chain区块链接口提供RPC 和 REST两套接口,方便开发者与链进行对接,接口详细设计请查看DPR Chain接口文档。其主要接口如下:
  • 查询当前连接的节点信息接口
  • 广播交易接口
  • 查询最新区块接口
  • 根据高度查询区块接口
  • 根据交易Hash查询交易接口
  • 查询交易事件接口