波卡在设计之时,以太坊就已经运转多年,以太坊之前的设计所衍生出的问题,也激发了波卡在设计时采取不一样的结构和实现方式。通过对波卡协议进一步的了解,我们可以感受到这些全新的设计背后的原因如何,又带来了怎样的全新效果。本期,我们继续介绍波卡协议中的外源和事件。
区块格式
波卡进行了一次投票,该投票于2020年7月27日结束(区块888888),在投票中,利益相关者决定重新设定DOT通证的货币单位。重新设定并不改变网络中的基本单位(在波卡中称为“plancks”)的数量。唯一的改变是,单个DOT通证将是1e10 plancks,而不是原来的1e12 plancks。请参阅波卡的博客文章以了解详细信息和投票结果:一个波卡的区块由区块头和区块体组成。区块体由表示交易概念普遍性的外源(Extrinsics)组成。外源可以包含底层链希望验证和跟踪的任何外部数据。译者注:Extrinsics可以理解为外部交易数据,本文用外源来指代。区块头是一个包含以下5种元素的组:
- parent_hash:SCALE编码的父区块头的32字节Blake2b哈希。
- number:表示当前区块在链中的索引的整数。它等于祖先块的数量。创世状态的数字为0。
- state_root:Merkle树的根,用作系统存储。
- extrinsics_root:保留给Runtime验证组成区块体的外源完整性的字段。
- digest:用于存储任何特定链的辅助数据的字段,这可以帮助轻客户端在不需要访问完整存储的情况下与块进行交互,以及包括块签名在内的共识相关数据。
创建或接收区块的节点必须将该区块广播到网络(即其他节点)。网络中的其他节点将跟踪此通告,并可以请求有关该区块的信息。关于这一过程的更多细节在Polkadot Spec中有详细说明:https://spec.polkadot.network/#sect-msg-block-announce
外源(Extrinsics)
外源是一个SCALE编码数组,包含版本号(Version Number)、签名(Signature)和不同的数据类型,指示要调用的Runtime函数,包括执行该函数所需的参数。外源代表来自外部世界的信息,分为三种形式:
- 固有的
- 已签名交易
- 未签名交易
作为基础设施提供者,您几乎只处理已签名的交易,但您会在解码的区块中看到其他外源。详见Substrate文档:https://docs.substrate.io/build/tx-weights-fees/固有的外源是未签名的,包含无法证明是否为真的信息,但验证者基于某种合理性标准达成一致。例如,时间戳无法证明,但验证者可以同意它与他们系统时钟的差值在一定范围内。固有外源作为生成的区块的一部分广播,而不是作为独立的外源被广播。已签名交易包含发布交易的账户的签名,并且需要支付费用才能将交易包含在链上。因为在执行前可以识别包含已签名交易的价值,它们可以在网络中的节点之间以低风险的形式传播。已签名交易符合以太坊或比特币中的交易概念。一些交易不能由支付费用的账户签名以及使用未签名交易。例如,当用户从以太坊DOT指示合约中认领其DOT到新的DOT地址时,新地址没有足够的资金来支付费用。波卡主机(Polkadot Host)不限制外源的内部细节,这些是由Runtime定义和处理的。
交易死亡率
译者注:交易死亡率,即Transaction Mortality,是指在区块链系统中,一笔交易一旦被广播出去,由于某些原因未被包含在区块中的比率。交易死亡率的高低可以说明区块链系统的效率,以及区块容量和网络负载的状况。较低的交易死亡率通常表明区块链系统稳定性较高,而高交易死亡率则表示系统可能存在瓶颈或其他问题。外源(Extrinsics)可以是非永久的或永久的。交易有效载荷(Transaction payload)包括交易有效的区块编号和区块哈希检查点,以及表示交易有效的检查点之后的区块数量的有效期(在某些地方也称为“era”)。如果该外源在此有效窗口内未被包含在区块中,则将从交易队列中丢弃。链只存储了一定数量的先前区块哈希作为参考。您可以从链状态或元数据查询这个称为BlockHashCount的参数。该参数在起源处设置为区块blocks(大约七个小时)。如果有效期大于链上存储的区块数,则交易仅在有区块进行校验时才有效,即有效期和区块哈希计数的最小值。将区块检查点设置为零,使用起源哈希,并将有效期设置为零,将使交易变为“永久”的。注意一点,如果一个账户被收回并且用户重新为该帐户注资,那么他们可以重播一个永久的交易。始终默认使用非永久的外源。
外源的唯一标识符
注意,假定交易的哈希是唯一标识符是索引服务和托管人犯的第一个错误。这个错误将对您的用户造成重大问题。请确保您仔细阅读本节。现有区块链上的许多基础设施提供商,例如以太坊,将交易的哈希视为唯一标识符。在像波卡这样的基于Substrate的链中,交易的哈希仅作为交易信息的指纹,有时存在具有相同哈希的两笔交易都是有效的情况。在其中一笔交易无效的情况下,网络会正确处理交易,不向发送方收取交易费用,也不将交易纳入到区块的完整性中。请想象一个关于被收割账户的编造示例。第一笔和最后一笔交易是相同的,都是有效的。译者注:被收割的账户是指如果一个账户低于存在存款ED,它将被收割,即从存储中完全删除并重置nonce。
此外,并非基于Substrate的链中的每个外源都来自作为公钥/私钥对的账户;相反,Substrate具有调度“来源”的概念,它可以从公钥账户创建,但也可以通过其他方式(例如治理)形成。这些来源没有像账户那样与它们相关联的随机数。例如,治理可能会多次使用相同的参数分派相同的调用,例如“将验证者集增加10%”。这个调度信息(因此它的哈希)将是相同的,并且该哈希将是调用的可靠代表,但它的执行会产生不同的效果,具体取决于调度时链的状态。在基于Substrate的链上唯一识别外源的正确方法是使用区块 ID(高度或哈希)和外源的索引。Substrate将一个区块定义为一个区块头和一个外源的数组;因此,数组中处于规范高度的索引将始终唯一识别一次交易。这种方法反映在Substrate代码库本身中。
活动
外源(Extrinsics)代表来自外部世界的信息,而活动(Events)代表来自链的信息。外源可以触发事件。例如,例如,当领取抵押奖励时,Staking模块会发出一个Reward事件,告诉用户账户被存入了多少。如果您想监控地址的存款,请注意,几笔交易可以启动余额转移(例如balances.transferKeepAlive和带有内部转账的utility.batch)。仅监控balances.transfer交易是不够的。请确保您监视每个区块中的事件,以查找包含您感兴趣的地址的事件。监控事件而不是交易名称,以确保您可以正确记入存款。
费用
波卡使用基于权重(weight)的费用,与gas不同,它是在发起前收取的。用户还可以添加“提示tip”以在拥塞期间提高交易优先级。有关详细信息,请参阅交易费用页面:https://wiki.polkadot.network/docs/learn-transaction-fees
编码
Parity的集成工具应该允许您处理解码数据。如果您想绕过它们并直接与链数据交互或实现您自己的编解码器,波卡使用SCALE编解码器对区块和交易数据进行编码。SCALE编解码器相关页面:https://docs.substrate.io/reference/scale-codec/波卡在设计时就考虑了之前的一些公链走的弯路。于是有了许多全新的设计,比如在交易费方面就与以太坊体系的gas费设计思路不同,采用了全新的weight权重来计算。此外,传统公链会遇到的一个严重的问题就是升级需要硬分叉,这一点波卡也有创新的设计,最终实现了无硬分叉就可以升级的功能,关于Runtime更多的信息,将在我们下一期的科普中为大家详细介绍。