Home
Welcome to the controller_poc wiki!
Controller
是整个区块链系统的中枢,负责所有核心流程(出块,同步等)。基本只有Controller
会主动发起流程和相关的接口调用,相比之下,其他微服务都处于被调用的位置。
创世块本质是一个配置文件,里面配置了高度为0的创世块的内容。因为目前版本没有智能合约的功能,系统配置有另外单独的配置文件,因此创世块里只有timestamp
和prevhash
两项内容。
初始化的时候会读取配置文件,然后生成相应的块结构。
本实现的区块链系统同时支持account
和utxo
两种类型的交易。但是utxo
类型的交易只用于系统配置管理。
初始化时需要一个单独的初始系统配置,给系统配置项赋予初值。
在一个块确认之后,如果发现有utxo
类型的交易,会调用本模块的update
函数更新系统配置。
交易池负责维护尚未确认的交易。本实现就简单的使用HashSet
来保存这些交易的hash
,另外有一个HashMap
给每笔交易赋予一个序号。
因为要支持pow
之类没有最终确定性的共识算法,交易池直到块最终确认(后面累计block_delay_number
个后续块),才会将交易从交易池中删除。
为了尽量避免打包重复的交易,打包交易的时候是随机选择交易的。具体做法是随机选择一个开始的序号,然后往后顺序扫描,直到没有交易,或者交易数量达到打包上限。
auth
主要负责检查交易的合法性,包括交易中每个字段的合法性,以及与历史交易是否重复。同现在的cita
一样,auth
会保存最近100个历史块中的交易hash
。
对于utxo
类型的交易的交易,还要校验prevhash
是否正确。
chain
主要是维护了一个管理未最终确认块的fork_tree
。因为链的未确认部分长度是确定的(block_delay_number
),因此fork_tree
是一个HashMap
,以index
(块高-已经确认的最高块高)为key
。其总长度为block_delay_number * 2 + 2
,主要是考虑节点落后的情况下,可以尽量多的同步未来的候选块,加快同步的速度。
本实现比较简单,并没有分叉链之间切换的逻辑。而是在一个块得到确认之后,按照prevhash
临时找出对应的分叉链。如果该分叉链比之前的主链要长,则进行替换,并更新一些相关的状态。
如果新的主链长度大于block_delay_number
,则多出的部分最老的块得到最终确认,会将相关信息写入storage
,并更新当前块高/块hash
等信息。
新确认的块有两个来源:一个是共识微服务通过commit_block
提交的块,另外一个是同步过来的块。只不过共识提交的确认块在未最终确认的区域,而同步过来的块是已经最终确认的。同步块的处理基本与上述相同,额外的会清理掉当前的主链,因为最新的当前块变化之后,原来的主链肯定跟它连不上了。
候选块除了刚启动初始化时会主动增加,后续是每次有新的块最终确认才会增加新的候选块。同步块的处理没有这个操作,因为处于同步状态意味着本节点落后了,那么主链和候选块很可能是没有意义的。
本实现没有自己实现同步协议,而是使用了一个成熟的文件同步工具(syncthing
)。针对要同步的内容(tx
,proposal
,block
)分别创建了同步文件夹。
将要同步的内容写入对应的文件夹,就会自动同步到其他节点。接受方使用inotify
监控文件变化,有新的文件之后会生成通知事件。
有一个单独的任务,定时拉取通知事件,根据事件类型的不同,分别调用不同的处理函数。
区块链的核心流程有同步和出块。
同步在本地实现里面使用了已有的软件,大致情况前面已经讲过,这里略过不谈。
出块其实就是将用户提交的原始交易数据,组装成共识模块需要的提案,经过共识并最终确认之后,写入storage
持久化的过程。
为了减少共识过程中带宽的消耗,最终共识的提案只是一个哈希值。从用户提交的原始交易数据到提案,经过了两次处理。即原始交易数据到compact block
,和compact block
到提案。
用户通过rpc
接口提交原始交易数据,经过auth
进行合法性验证,进入pool
。需要提案的时候,从pool
中打包一批交易,compact block
中存放交易的哈希。
本实现中,block header
中并没有proof
和executed block hash
字段。而是在由compact block
形成提案的时候,将上一个块的proof
和executed block hash
计算在内。
这些过程可以随着具体设计的不同而变化,但是整个过程要保证是可验证的,以便其他节点收到候选块的时候可以验证。