外部调用
一个外部调用是一些区块中包含的来自区块链外部的信息。 外部调用主要分为三类: 固有信息,签名交易和无签名交易。
请注意,events 不是外部调用。 链针对链本身的一些信息发出的事件,例如质押奖励是事件,而不是外部调用,这是因为奖励是由链内在的逻辑判断触发的。
区块结构
Substrate中的区块由区块头和一组外部调用组成。 区块头包含块高度,父哈希,外部根,状态根和摘要。 本节仅关注外部根。
所有的外部调用会被打包进一个区块,从而形成一个外部序列并依次被runtime执行。其中外部根是该序列的摘要,它主要有两个目的: 首先,它可以防止在区块头已构建并被分发后,对外部序列进行任何更改;其次,它允许轻节点仅通过区块头,就可以简洁地验证任何给定的外部调用是否存在于一个块中。
固有信息 (Inherents)
固有信息是只能由出块者创建并插入到区块中的未签名的信息,它们不会被散布在网络中或存储在交易队列中。 从技术上讲,基于Substrate的链可以传播任意固有信息,并且也不会有基于交易费用的垃圾消息检测机制。
固有信息以一种主观的方式描述一些有效信息,这些信息之所被认为是“真实的”,仅仅是因为有足够多的验证人都认为它是合理的。
例如,出块者可以将固有的时间戳插入块中, 没有办法像交易那样通过签名验证,来证明时间戳是正确的。验证者则是根据其他验证者是否认可时间戳(也就是说,该时间戳在验证者自己的系统时钟的某个可接受范围内)来接受或拒绝该块。
签名交易
签名交易包含发出交易帐户的签名,并且需要支付交易费才能被打包上链。由于在交易执行前就可以知道交易费,所以在网络节点中传播此类垃圾交易的风险很小。
Substrate 中的签名交易与以太坊或比特币是一样的。
无签名交易
有些情况下需要使用无签名交易,但是因为它的验证难度很大,所以要谨慎使用无签名交易。
由于不需要签名,因此没人会支付交易费,这使得交易队列无法用有效的经济手段,来防止滥用无签名交易。 再者,无签名交易中缺失nonce字段来声明交易执行顺序,从而难以防止“重放攻击”。 少数交易能安全地以无签名的形式执行,但是它们需要通过预先自定义signed extension来防止垃圾交易,这里signed extension可以用于无签名交易。
Substrate 中一个无签名交易的例子,就是由验证节点定时发送的 I'm Online心跳交易。 该笔交易虽然包含了一个会话密钥签名,但会话密钥并不能控制资金,因此也就无法支付交易费用。 交易池通过检查验证人在某个session内是否提交过心跳交易,来防止垃圾信息(如果提交过会拒绝新的心跳交易)。
签名拓展(Signed Extension)
签名扩展
是Substrate的一个特性 ,通过它可以使用额外的数据或逻辑来扩展交易。 使用签名扩展可以实现在交易执行之前获取某笔特定交易信息。 因此,交易队列中大量使用"签名扩展"。
Runtime中会使用“签名扩展”提供的一些数据,比如调用Call
函数的数据计算交易费用。 签名扩展还包含一个名为AdditionalSigned
的字段,该字段可存放任意可编码数据,因而允许用户在打包或者发送交易之前,执行自定义逻辑。交易队列还会定期调用 SignedExtension
中的函数来验证即将被打包的交易, 以避免将可能失败的交易打包进区块中。
尽管带 签名拓展
包含“签名”两字,但其实它也可以用于验证无签名交易。 我们可通过实现 *_unsigned
的一系列方法,来封装交易池所需的信息核验、防垃圾信息和重放保护等逻辑。