概况
区块链是一个分布式的记账系统,在一个区块链系统中可以有成千上万的节点,他们各自独立保存一份相同的账本,而新的交易数据想要被写入帐本,需要获得这些节点的认可。在不可信的分布式环境中实现这一目标是一个很复杂的系统工程。区块链系统正常运行,即区块链中各节点总能保存同一份账本,前提是系统中绝大部分的节点是诚实可靠的。为了保证诚实可靠的节点能够共同监督交易数据写入账本,每个区块链系统都需要构建自己的共识,共识就相当于区块链的宪法。共识保证了即便是在不可信的分布式环境下,只要绝大多数节点遵守共识的规定,就一定能获得确定可信结果。因此共识的意义在于,区块链中的诚信节点可以最终达成账本的一致只要他们严格遵守这份共识。
共识有多种类型,目前使用最多的是POW、POS、DPOS,当然不同的区块链系统中都会有一些特有的具体实现上的不同。本文主要介绍波场的共识就是基于DPOS的,同时向大家说明一下DPOS中的基本组件和机制。
记账流程
区块链系统的记账人,他们收集区块链网络中新产生的交易,并对这些交易的合法性进行验证,然后把这些交易打包在一个区块中,作为新的一页账记录在账本上,然后将账页在整个区块链网络中进行广播,其他的节点收到新的账页,也会验证账页中交易数据的合法性,并添加到自己的账本中。记账人一直重复这个过程,这样只要区块链系统中新的交易数据都会记录在账本里面
DPOS概述
共识的作用是在区块链系统中选出记账人,记账人验证交易数据并进行记账,进而向区块链网络中的其他节点广播新的账目,并获得其他节点对于新账目的认可。DPOS作为共识的一类特定实现是这样的:
DPOS共识在区块链系统中根据节点获取选票的多少确定出部分节点作为记账。首先区块链系统开始启动运行的时候,会发行一定数量的通证,然后将通证分给区块链系统中的节点,节点可以凭借一部分通证申请成为这个区块链系统记账人的候选人,区块链系统中任何持有通证的节点都可以为这些候选人进行投票,每经过一段时间t会统计所有候选人获得的选票数量,选票数量排在前面的N个节点会成为下一段时间t内的记账人,再经过t的时间,又会重新统计一遍新的记账人,以此类推循环往复。
定义
波场
指波场的区块链网络。本文不区分波场、波场区块链、波场区块链系统等概念。
波场币
指由波场区块链系统发行并在系统中流转的权益通证,代号是TRX。
记账候选人
指波场中有成为记账人资格的节点。
记账人
指波场中获得记账资格的节点,通常DPOS共识中将记账人称为witness,波场也将记账人称为super node(简称SR),波场设定记账人的数量是27个。下文不区分记账人、witness、supernode、SR等概念。
记账
指验证交易并将交易记录成账目的过程,由于波场中的账目是用区块承载的,因此记账的过程也被称为生产区块,下文不区分记账和生产区块。
记账顺序
即出块顺序。按照27个记账人得票多少的降序作为记账顺序。
区块时间
波场中设定一个区块时间是3秒钟,即每3秒会生产出一个区块。
槽位
每一个区块生产出来可以放到一个槽位,被称为slot,每当一个区块生产出来就会占用一个槽位。例如,1分钟有20个slot,当1个区块时间内有1个区块生产出来,对应的slot会被填满,如果没有区块被生产出来,那么对应的slot就是空的,下个区块生产出来的时候会填充到新的对应的slot中。
出块轮
波场设定每6个小时作为一个出块轮,称为一个Epoch。每个出块轮最后的2个出块时间是一个维护期。每个出块轮的维护期决定下一个出块轮的出块顺序。
维护期
波场设定是2个区块时间,即6秒钟。这段时间用于统计候选人得票数。因为24个小时有4个出块轮,自然就有4个维护期,维护期中不进行区块生产,主要用来确定下个出块轮的出块顺序。
选举机制
选票
波场中设定拥有一个TRX就可以拥有一张选票的权利。
投票过程
波场中设定对候选人的投票过程是一笔特殊类型的交易,节点可以通过生成一笔投票交易对候选人进行投票。
统计票
每个维护期内,统计一次候选人的票数,将获得票数最多的27个候选人作为下一个出块周期的记账人。
产块机制
在一个出块轮中,27个记账人按照记账顺序依次生产区块。每个记账人只能在轮到自己产块时进行区块生产,记账人将多笔验证合法的交易数据打包到每个区块之中,同时每个区块都会将上个区块的哈希值(hash)作为本区块的父哈希值(parentHash)填入区块中,同时用自己的私钥对本区块的数据进行签名,将签名结果(witness_signature)也填入区块中,同时被填入区块的还有记账人的地址,区块高度,区块生成的时刻等数据。
通过每个区块保存了上个区块hash值的方式,从而在逻辑上将区块相互关联了起来,最后组成了一条链的结构
理想情况下,采用DPOS共识的区块链系统的记账过程就是按照事先计算好的记账顺序,由witness轮流依序产块,但实际情况下,区块链网络是一个分布式的、不可信的复杂系统,体现在
1)由于网络链路环境不佳导致witness生产的区块并不会在有效时间内被其他的witness收到;
2)并不能保证某个witness运行始终正常;
3)某些witness恶意生产分叉的区块企图将链分叉。
前文已经提到区块链系统正常运行的基础是系统中绝大部分的节点是诚实可靠的,再进一步探讨这个问题,区块链系统安全的首要保证的是账本的安全,账本既不能被恶意写入不合法的数据,账本在各个节点上保存的副本也应该是一致的。如果从DPOS共识的角度上来看,记账过程是由witness完成,因此波场的安全取决于大部分witness的可靠性,波场设定了不可逆转区块,也称为固化块。同时为了抵抗少部分记账节点的恶意行为,波场采用基于最长链的原则确认为主链
固化块原则
刚生产出来的区块处于未确认状态,只有被27个Witness中70%以上(即27 * 70% = 18, 向下取整)的witness"认可"的区块才被认为是不可逆区块,一般称为固化块,此时固化块中包含的交易已经被整个区块链网络确认。此处对未确认状态区块"认可"的方式是Witness在其之后生产后继区块,如图d中Witness C生产的第103块,Witness E在第103块的基础上生产了104‘,Witness G、A、B分别生产的第105‘、106’、107‘实质上也是103块的后继区块,故也是对C生产的第103块的认可。可知,当高度为121的区块被生产出来的时候,第103块就成为固化块,因为此时103区块已经有了18个后继区块,此处需要强调的一点是:生产这18个区块的Witness互不相同,并且和生产第103个区块的Witness也不同
最长链原则
当区块链产生分叉之后,诚实的witness总是选择在当前最长的那个分叉链上继续生产区块
激励模型
为了保证区块链系统安全高效地运行,波场设定激励模型用于鼓励更多的节点加入到波场网络中,从而扩大网络规模,对于记账人当他们完成出块任务,给予相应的TRX奖励。波场设定witness每生产一个被固化的区块,就会获得32个TRX的奖励;对于所有记账人(包括记账候选人)的得票在前127名的,每个Epoch的维护期会依据得票率的多少分配固定的奖励.
超级代表
TRON网络中有27个出块者,即超级代表。
任何账户都可以申请成为超级代表候选人。每个账户都可以投票给超级代表候选人,获取投票数最高的27个候选人就是超级代表,第28~127名为超级合伙人。超级代表会有出块和打包交易的义务,同时也会获得相应的投票和出块奖励,并且有权力参与波场网络动态参数提议的投票。100名超级合伙人可以获得投票奖励。
超级代表和激励机制
选举超级代表
用户需要获得投票权来给超级代表投票,即TRON Power(TP)。TP的数量取决于选民的冻结资产(TRX),1 TP = 冻结1TRX。
在释放(解冻)之后,会失去对应的TP,同时正在进行的和对于未来的投票都将失效。
TRON网络只记录最近一次的投票,之前的投票会被覆盖。
投票统计每6小时统计一次,超级代表和超级合伙人也就每6个小时变更一次。票数排名前27位为超级代表,排名28-127为超级合伙人,排名128以后为超级代表候选人。
根据TRON网络的规则,申请成为超级代表需要燃烧9999个TRX,以此来预防恶意的行为。
奖励
超级代表奖励: 波场网络每3秒生成一个区块,每个块将16个TRX授予出块的超级代表。
投票奖励:波场网络每生成一个区块, 127名超级代表和合伙人将按照获得的投票比例瓜分160TRX,每6小时共产生奖励1152000TRX。 每年投票的总奖励额约为 1,681,920,000 TRX。超级代表和合伙人获得的投票奖励也会根据佣金比例扣除后按照选民投票比例分配给选民。
在2021年1月1日之前,TRON网络将不会出现通货膨胀,TRON基金会将在该日期之前提供100%的区块奖励和候选人奖励。
每当超级代表完成出块时,奖励将会打到超级账本中的子账户。 超级代表可以查看,但不能直接使用此资产。 可以每24小时取款,把奖励从子帐户转移到超级代表的帐户。
奖励计算
奖励总额=投票奖励 x (佣金比例) +出块奖励 x (佣金比例)
超级代表佣金
默认比例20%,另外80%分发给选民。超级代表可通过接口修改该数值。
投票奖励
每个区块给予160个TRX作为投票奖励。
投票统计数据每6小时计算一次,超级代表根据投票结果而变化。
对于所有127名超级代表候选人,每日共投票奖励:
160(TRX /块)x 7200(块/选举)x 4(选举 /天)= 4608,000(TRX /天)1。
对于每位候选人,每日投票奖励= 4,608,000 x(SR获得的投票/全网总票数)x 20%
由于可能的丢块,Reward 可能会小于理论数.
出块奖励
SR逐个出块,出块奖励为每个区块16个TRX。
对于所有27位超级代表,每日共出块奖励:
16(TRX /块)x 7200(块/选举)x 4(选举 /天)= 460,800(TRX /天)
对于每位超级代表,每日出块奖励=460,800 / 27 x 20%= 3413 TRX
选民奖励
以默认的超级代表或超级合伙人佣金比例计算,80%的奖励分发给了选民,每个投票对应每6小时的奖励= 80% x 7200(块/选举) x 160 /total votes + 80% x 7200(块/选举) x 16 / 27 / sr votes)。total votes为全网总投票数,sr votes为超级代表获得的投票数。因此每个选民需要知道超级代表佣金率、全网总投票数和sr获得的投票数就可以计算奖励,此数据会对所有人开放。
基于提案对参数进行调整
DPOS的一个重要的特性是任何系统参数的调整都可以通过链上的提案发起,记账人通过对提案的投票来决定提案是否生效。这样的好处是在链上新增加一些特性不需要进行硬分叉升级,波场目前能够支持的系统参数调整有:
# | Command | Value |
---|---|---|
0 | getMaintenanceTimeInterval (修改超级代表调整时间间隔) |
6 Hours [3 27, 24 3600] s |
1 | getAccountUpgradeCost (修改账户升级为超级代表的费用) |
9999 TRX [0, 100000000000] TRX |
2 | getCreateAccountFee (修改创建账户费用) |
0.1 TRX [0, 100000000000] TRX |
3 | getTransactionFee (修改TRX抵扣带宽的费用) |
10 Sun/Byte [0, 100000000000] TRX |
4 | getAssetIssueFee (修改资产发行费用) |
1024 TRX [0, 100000000000] TRX |
5 | getWitnessPayPerBlock (修改超级代表出块奖励) |
16 TRX [0, 100000000000] TRX |
6 | getWitnessStandbyAllowance (修改分给前127名超级代表候选人的奖励) |
115200 TRX [0, 100000000000] TRX |
7 | getCreateNewAccountFeeInSystemContract (修改系统创建账户的费用) |
0 TRX |
8 | getCreateNewAccountBandwidthRate (提议7、8,组合使用,用于修改创建账户时对资源或TRX的消耗) |
1 Bandwith/Byte |
9 | getAllowCreationOfContracts (控制虚拟机功能的开启 ) |
1 {0, 1} |
10 | getRemoveThePowerOfTheGr (用于清除GR的创世票数) |
1 {0, 1} |
11 | getEnergyFee (修改能量费用) |
10 Sun [0, 100000000000] TRX |
12 | getExchangeCreateFee (修改创建交易对的费用) |
1024 TRX [0, 100000000000] TRX |
13 | getMaxCpuTimeOfOneTx (修改交易最长执行时间) |
50 ms [0, 1000] ms |
14 | getAllowUpdateAccountName (允许用户更改昵称以及昵称同名) |
0 {0, 1} |
15 | getAllowSameTokenName (允许创建相同名称的token) |
1 {0, 1} |
16 | getAllowDelegateResource (控制资源代理功能的开启) |
1 {0, 1} |
18 | getAllowTvmTransferTrc10 (允许智能合约调用TRC10 token的接口) |
1 {0, 1} |
19 | getTotalEnergyCurrentLimit (修改ENERGY总量) |
50000000000 |
20 | getAllowMultiSign (允许开启多重签名) |
1 {0, 1} |
21 | getAllowAdaptiveEnergy (允许ENERGY总量自适应调整) |
0 {0, 1} |
22 | getUpdateAccountPermissionFee (修改账户权限费用) |
100 TRX |
23 | getMultiSignFee (修改账户权限费用) |
1 TRX |
24 | getAllowProtoFilterNum (允许更新protobuf的数字) |
0 {0, 1} |
26 | getAllowTvmConstantinople (允许TVM支持君士坦丁堡更新) |
1 {0, 1} |
27 | getAllowShieldedTransaction (允许匿名交易开启) |
0 {0, 1} |
28 | getShieldedTransactionFee (修改匿名交易手续费) |
10 TRX [0, 10000] TRX |
29 | getAdaptiveResourceLimitMultiplier (用于修改动态能量最大值) |
1000 [1, 10000] |
30 | getChangeDelegation (修改更换委托机制) |
1 {0, 1} |
31 | getWitness127PayPerBlock (修改票数排名奖励) |
160TRX [0, 100000000000] TRX |
32 | getAllowTvmSolidity059 (允许虚拟机支持0.5.9版本的Solidity编译器) |
0 {0, 1} |
33 | getAdaptiveResourceLimitTargetRatio (修改能量目标值) |
10 [1, 1000] |
带宽和能量机制
资源模型
TRON网络中的资源有4种:带宽,CPU,存储和内存。得益于波场独有的内存模型,TRON网络中的内存资源几乎是无限的。
TRON网络引入了Bandwidth Point 和 Energy 两种资源概念。其中Bandwidth Point表示带宽资源,Energy表示CPU和存储资源。
注意:
系统交易仅消耗Bandwidth Point
智能合约的操作不仅要消耗Bandwidth Point,还会消耗Energy
带宽
交易以字节数组的形式在网络中传输及存储,一条交易消耗的Bandwidth Points = 交易字节数 * Bandwidth Point费率。当前Bandwidth Point费率 = 1。
如一条交易的字节数组长度为200,那么该交易需要消耗200 Bandwidth Points。
注意: 由于网络中总冻结资金以及账户的冻结资金随时可能发生变化,因此账户拥有的Bandwidth Points不是固定值。
Bandwidth Points的来源
Bandwidth Points的获取分两种:
- 通过冻结TRX获取的Bandwidth Point, 额度 = 为获取Bandwidth Point冻结的TRX / 整个网络为获取Bandwidth Points冻结的TRX 总额 * 43_200_000_000。 也就是所有用户按冻结TRX平分固定额度的Bandwidth Points。
- 每个账号每天有固定免费额度的带宽,为5000。
Bandwidth Points的消耗
除了查询操作,任何交易都需要消耗bandwidth points。
还有一种情况,如果是转账,包括普通转账或发行Token转账,如果目标账户不存在,转账操作则会创建账户并转账,只会扣除创建账户消耗的Bandwidth Points,转账不会再消耗额外的Bandwidth Points。
Bandwidth Points的计算规则
Bandwidth Points是一个账户1天内能够使用的总字节数。一定时间内,整个网络能够处理的Bandwidth为确定值。
如果交易需要创建新账户,Bandwidth Points消耗如下:
- 尝试消耗交易发起者冻结获取的Bandwidth Points。如果交易发起者Bandwidth Points不足,则进入下一步
- 尝试消耗交易发起者的TRX,这部分烧掉0.1TRX
如果交易是Token转账,Bandwidth Points消耗如下:
- 依次验证 发行Token资产总的免费Bandwidth Points是否足够消耗,转账发起者的Token剩余免费Bandwidth Points是否足够消耗,Token发行者冻结TRX获取Bandwidth Points剩余量是否足够消耗。如果满足则扣除Token发行者的Bandwidth Points,任意一个不满足则进入下一步
- 尝试消耗交易发起者冻结获取的Bandwidth Points。如果交易发起者Bandwidth Points不足,则进入下一步
- 尝试消耗交易发起者的免费Bandwidth Points。如果免费Bandwidth Points也不足,则进入下一步
- 尝试消耗交易发起者的TRX,交易的字节数 * 10 sun
如果交易普通交易,Bandwidth Points消耗如下:
- 尝试消耗交易发起者冻结获取的Bandwidth Points。如果交易发起者Bandwidth Points不足,则进入下一步
- 尝试消耗交易发起者的免费Bandwidth Points。如果免费Bandwidth Points也不足,则进入下一步
- 尝试消耗交易发起者的TRX,交易的字节数 * 10 sun
带宽的自动恢复
在网络总锁定资金以及账户锁定资金不变的情况下,账户的带宽的已使用量随着时间增加而按比例衰减,24h衰减到0。如时间T1时刻,账户带宽已使用量为U,到T1+12h,账户再次使用带宽u,此时账户已使用带宽为 U/2 + u。具体公式如下:
即可以理解为每24h,用户已使用的带宽值重置为0
能量
智能合约运行时执行每一条指令都需要消耗一定的系统资源,资源的多少用Energy的值来衡量。
Energy的获取
冻结获取Energy,即将持有的trx锁定,无法进行交易,作为抵押,并以此获得免费使用Energy的权利。具体计算与全网所有账户冻结有关,可参考相关部分计算。
FreezeBalance 冻结获得能量
通过冻结TRX获取的Energy, 额度 = 为获取Energy冻结的TRX / 整个网络为获取Energy冻结的TRX 总额 * 50_000_000_000。
也就是所有用户按冻结TRX平分固定额度的Energy
FreezeBalance 恢复能量
所消耗的能量会在24小时内平滑减少至0。
示例:
在某一时刻A的Energy已使用量为72_000_000 Energy,在没有其他消耗或冻结的操作下:
一小时后A的Energy已使用量为 72_000_000 - (72_000_000 (6060/606024)) Energy = 69_000_000 Energy
24小时后A的Energy已使用量为 0 Energy。
如何填写feeLimit
在本节范围内,将合约的开发部署人员,简称为“开发者”;将调用合约的用户或者其他合约,简称为“调用者”。
调用合约消耗的Energy能以一定比例折合成trx(或者sun),所以在本节范围内,指代合约消耗的资源时,并不严格区分Energy和 trx;仅在作为 数值的单位时,才区分Energy、trx和sun。
合理设置feeLimit,一方面能尽量保证正常执行;另外一方面,如果合约所需Energy过大,又不会过多消耗调用者的trx。在设置feeLimit之前,需要了解几个概念:
- 合法的feeLimit为0 - 10^9 之间的整数值,单位是sun,折合0 - 1000 trx;
- 不同复杂度的合约,每次正常执行消耗不同的Energy;相同合约每次消耗的Energy基本相同;执行合约时,逐条指令计算并扣除Energy,如果超过feeLimit的限制,则合约执行失败,已扣除的Energy不退还;
- 目前feeLimit仅指调用者愿意承担的Energy折合的trx;执行合约允许的最大Energy还包括开发者承担的部分;
- 一个恶意合约,如果最终执行超时,或者因bug合约崩溃,则会扣除该合约允许的所有energy;
- 开发者可能会承担一定比例的Energy消耗(比如承担90%)。但是,当开发者账户的Energy不足以支付时,剩余部分完全由调用者承担。在feeLimit限制范围内,如调用者的Energy不足,则会燃烧等价值的trx。
开发者通常会有充足的Energy,以鼓励低成本调用;调用者在估算feeLimit时,可以假设开发者能够承担其承诺比例的Energy,如果一次调用因为feeLimit不足而失败,可以再适当扩大。
Energy的计算
- tron为了惩罚恶意开发者,对于异常合约,如果执行超时(超过50ms),或因bug异常退出(不包含revert),会扣除本次的最大可用Energy。若合约正常执行,或revert,则仅扣除执行相关指令所需的Energy;
- 开发者可以设置执行合约时,消耗Energy中自己承担的比例,该比例后续可修改。一次合约调用消耗的Energy,若开发者的Energy不足以支付其承担的部分,剩余部分全由调用者支付;
- 目前执行一个合约,可用的Energy总数由 调用者调用时设置的feeLimit 和 开发者承担部分共同决定
注意:
- 若开发者不确定合约是否正常,请勿将用户承担比例设置为0%,否则在被判为恶意执行时,会扣除开发者的所有Energy。
- 因此建议开发者设置的用户承担的比例为10%~100%。
如果合约执行成功,没有发生任何异常,则会扣除合约运行实际消耗的Energy,一般都远远小于此次调用能够使用的Energy。如果发生了Assert-style异常,则会消耗feeLimit对应的所有的Energy。
注意:
开发者创建合约的时候,consume_user_resource_percent不要设置成0,也就是开发者自己承担所有资源消耗。
开发者自己承担所有资源消耗,意味着当发生了Assert-style异常时,会消耗开发者冻结的所有Energy。
资源委托
在TRON中,一个账户可以通过冻结TRX来获取带宽和能量。同时,也可以把冻结TRX获取的带宽或者能量委托(delegate)给其他地址。
此时,主账号拥有冻结的TRX以及相应的投票权,受委托账户拥有冻结获取的资源(带宽或者能量)。
和普通冻结一样,委托资源也至少冻结3天。
参考文档
https://tronprotocol.github.io/documentation-zh/introduction/dpos/
https://cn.developers.tron.network/docs/%E8%B5%84%E6%BA%90%E6%A8%A1%E5%9E%8B