5 块的生命周期
特定的BP在特定的时间段生产块,然后将块广播到其他BP,收到的BP校验块。这个过程会一直持续,直到下一个轮次的到来。
当一个块满足共识条件,即大多数BP校验通过(2/3 + 1),这个块会变成不可逆状态。
因此,块经历三大阶段:生产,校验,终态(不可逆状态)。每个大阶段(phase)又会经历各种小阶段(stage)。
5.1 块结构
块是区块链的基本单位,每个块指向前一个块,从而形成了区块链。
块中包括若干交易(transaction),每个交易又包括若干行为(action),一个交易中的若干行为具有原子性,即这些行为要么都成功,要么都失败。
块中除了交易,还包含生产者的签名,块hash,防止重放攻击等信息。
块的具体信息参见:https://developers.eos.io/welcome/latest/protocol/consensus_protocol/#block-schema
可以对照:https://eospark.com
eosio允许有空块,即不包含任何交易的块。例如:https://eospark.com/block/1898855
5.2 块生产
当前,每个块被生产的时间是0.5s。为了确保有足够的时间在0.5秒生产块,并将块广播给其他节点校验,块生产时间被细分为以下两个参数:
最大处理时间(maximum processing interval):当前被设置为0.2秒,即将交易打包到块的时间,属于本地处理时间
最小广播时间(minimum propagation time):当前被设置为0.3秒,即将块广播出去的时间,属于网络通信时间
所以,EOS不像BTC那样限制块大小,而是限制块的打包时间?
所有未过期的交易,或者由于之前的无法校验(注意,是指无法校验,而不是校验失败)的交易,会被保存在本地队列中,为了后续将该交易加到块中。
在块生产期间,生产者应用(apply)并校验(validate)交易,如果有效,就在指定的最大处理时间内,将交易追加放到块中。如果过了最大处理时间,就将交易放到下一个块中。如果当前生产者要生产的块数(6 / 0.5 = 12个)到了,剩的交易就同步到其他BP。
如果当前正在生产块的BP要生产的是这一轮次的最后一个块,它的最大处理时间(即0.2秒)会稍微小一点,用来补偿切换到下一个生产者的网络延时。
生产过程中,如果到了最大处理时间,就不会将更多的交易追加的块中了。在块被广播给其他BP之前,块会经历一个确认(finalization)过程。
在生产这个大阶段过程中,细化的话,会经历应用、确认、签名和提交4个小阶段。
5.2.1 应用
应用是指BP将收到并校验过的交易放到块中。
这一过程涉及块头和签名块实例(the signed block instance)的创建和初始化。签名块实例通过签名字段(signature field)扩展块头。
值得注意的是,块结构体中的某些字段是在一开始就能确定的,例如timestamp,block_num,producer,previous等,有些字段依赖块中相关内容,例如tansaction_mroot,action_mroot,block_hash,producer_signature等。
另外,EOSIO最近允许包含多重签名(multiple signatures),多重签名被存储在header_extensions字段中。
5.2.2 确认
官网原文是Finalize,乍一看貌似是不可逆的意思,其实不是,这里只是对上一步放入块中的交易进行确认。所以个人觉得翻译成确认(或者确定)更好些。
在块被签名、提交、转发和验证之前,需要完成确认工作。
在确认过程中,块头中需要被校验的任何字段被计算并存储到块中。官网中没有明确指出哪些字段,个人理解应该是除了签名字段外的其他字段,包括生成tansaction_mroot和action_mroot,是指交易或动作产生的收据(或叫回执)数据的merkle root hash。
5.2.3 签名
是指对序列化后的块头和交易的收据数据,通过生产者的私钥,计算出签名信息,并填到block的签名字段。
5.2.4 提交
完成签名之后,一个具备完整信息的块就产生了。提交是指将完整的块提交到本地的链中,即”上链“。
这个过程会将块推送到可逆的块数据库(reversible block database)中。这使得该块可以和其他节点同步。
5.3 块校验
前面说过,块经历三大阶段:生产,校验,终态(不可逆状态)。上面说了生产,这一小节开始学习校验。
生产的整个过程都是在BP本地执行的,然后会将块广播到其他BP,其他BP在自己机器上进行校验。
校验的过程简单说就是,BP接收其他生产者发来的块,校验块中的每个交易。
校验是关于在活跃生产者之间达成以下共识:
● 块及其包含的事务的完整性
● 每个块中事务的确定性、时间顺序
当BP收到块之后,就开始校验。如果这个块是无效的,比如没有连接到一个有效的块,块ID重复等,这个块会被抛弃。
如果这个块是新的,它就被推送到链控制器(chain controller)去处理。
5.3.1 推送块
当块被链控制器收到后,就会决定把块放到本地链的什么位置。Fork DB(分叉数据库)就是干这个用的。Fork DB维护着所有”分叉“数据,即可逆块的所有分支。可逆块,顾名思义,就是还没有变成不可逆块。
具体流程如下:
1、将块加入到Fork DB
2、如果块被加到了包含current head block(可理解成一个指针,指向当前分支中最长链的最新的块)的主分支上,就应用该块(5.2.1);否则
3、如果块被加到其他分支,则
1、该分支和当前的主分支相比,如果该分支变成了首选分支(preferred branch),将主分支的所有块回滚(rewind)到最近的公共祖先(并且回滚数据库状态),重新应用这个分支中的所有块,添加新块并应用它。该分支现在变成了新的主分支。
如何变成首选分支?为啥需要回滚?个人理解,因为要修改主分支,就需要将老的主分支上的所有交易状态回滚,类似将交易撤销吧
2、该分支没有变成首选分支,啥也不做,除了将块加到这个分支上
在将块加入到Fork DB之前,需要对块头做一些校验。而如果块需要被应用(比如块所在的分支是主分支),块中的交易也必须被校验。
交易校验的程度要依赖于nodeos的配置,目前支持两个校验:全校验(默认模式,full validation)和轻校验(light validation)。
5.3.2 全校验
每个被应用的交易都会被充分校验。包括校验签名,检测权限等
5.3.3 轻校验
如果块是被自己配置的可以生产者签名的话,就会跳过交易校验。例如,会跳过签名认证,并假定所有的声明授权都是有效的。
5.4 终态
根据共识协议的aBFT层,如果一个块被大多数活跃的生产者校验,它就会变成了终态,即不可逆状态。变成终态的块就会被永久记录在区块链中,不能被撤销。这里有个术语很重要,后续会经常用到,即LIB(last irreversible block),是指最近刚刚变成终态的那个块。
5.4.1 终态的目的
主要目的是让用户确信,在LIB块之前应用的事务不能修改、回滚或删除。LIB块还可以帮助活跃的BP快速有效地确定从哪个分支构建,而不管哪个分支最长。这是因为给定的分支可能更长,但是却不包含LIB,即一个更短的分支如果包含LIB,也会被选为主分支的。
扩展
1、 eos如何防止重放攻击?
这块暂不是特别理解。从文档看,应该是和ref_block_prefix字段有关系。该字段来自transaction-id,具有一定的随机性。
2、block部分字段解读?
transaction_mroot checksum256_type merkle tree root hash of transaction receipts
action_mroot checksum256_type merkle tree root hash of action receipts
merkle tree是什么东东?
参考:https://www.cnblogs.com/s-lisheng/p/11301063.html
Merkle树大多用来进行完整性验证,比如分布式环境下,从多台主机获取数据,怎么验证获取的数据是否正确呢,只要验证Merkle树根哈希一致,即可。
一个关键作用:Merkle树还可以用来对数据进行快速比对,快速定位到不一致的数据。
iduint64_tUUID of this block ID (a function of block header and block number); can be used to query a transaction within the block
官网上说的id类型是uint64_t,但是通过eospark中发现是string,其实id就是这个block的hash值。
ref_block_prefix uint32_t lower 32 bits of id; used to prevent replay attacks
ref_block_prefix:从官网解释看,是id的低32位,因为官网上id的解释本身就有问题。
所以,实际上是id的某32位,从下面两个截图,应该可以发现规律。
图a:某block的id和ref_block_prefix字段
图b:ref_block_prefix转16进制后
网友评论