除了上面的同步形式外,区块链节点之间还存在另外两种特殊形式的同步,一种是交易同步,也就是当某个节点完成一笔交易后,需要向其他节点广播这个交易,另一种是矿工成功挖到一个区块,也要向其他节点广播这个新的区块。我们来看看这两种同步是怎么进行的。
交易同步
交易同步的数据包类型是TransactionsPacket
,EthereumPeer
收到这个包以后直接就在EthereumPeerObserver
里做了处理,并没有转交给BlockChainSync
,可能是因为这个处理太简单的缘故,我们也可以从代码中看出来:
1 | void onPeerTransactions(std::shared_ptr<EthereumPeer> _peer, RLP const& _r) override |
这里的处理就是放到m_tq
里,这里的m_tq
是TransactionQueue
对象,TransactionQueue
是一个专门放pending交易的队列,也就是还没有正式进入区块链的“无主”交易待的地方。关于这个类,后续会专门来讲。
新区块同步
新区块包的数据类型是NewBlockPacket
,这次处理的重任重新回到了BlockChainSync
,因此,我们来看看BlockChainSync::onPeerNewBlock
的处理吧。
这个处理分为两部分,第一部分是常规检查:
1 | if (_r.itemCount() != 2) |
这个包不同于之前的区块数据包,这个包里同时包含区块头和区块体,第一部分是对区块头里的信息进行处理。如果新收到的区块比我目前最新的节点更新,那么说明该节点有更新的数据,那么就调用syncPeer
从该节点进行同步。
第二部分就是导入区块体了:
1 | switch (host().bq().import(_r[0].data())) |
这里的流程和前一节差不多,将这个区块导入二级缓冲区中去验证。
几点补充
到这里ETH区块链同步的主要流程都涉及到了,剩下的部分单独再分析。本节再对同步补充几点:
- 以太坊ropsten网络比主网mainnet要差很多,对于同步来说就是噩梦。如果需要测试交易什么的建议自己搭建私有链来测试.
- 同步过程漫长,需要有耐心,而且是越来越慢,后期单个区块包含的交易更多,计算量和存储量都巨大。
- 同步硬盘建议SSD,容量在1TB以上。
- 同步存储主要是三类数据库,Block数据库,Extra数据库和State数据库,其中State数据库最大,这个就是所谓的世界状态了。
- 同步有坑!!!,还记得以太坊C++源码解析(五)区块链同步(2)里的那张图吗?整个流程有两个阀门,阀门1是从BlockQueue到区块链,阀门2是从网络到一级缓冲区。这两个阀门正常工作流程是这样的:当二级缓冲区里有数据时,阀门1开启,否则关闭;另外由于数据进入二级缓冲区的速度通常比从二级缓冲区进入区块链的速度要快很多,因此二级缓冲区里有大量数据,当二级缓冲区满时,阀门2关闭,否则开启。但是这两个阀门在实际测试中是存在故障的,阀门1故障的表现是数据校验后未打开,数据不会进入区块链,导致二级缓冲区一直满,从而导致阀门2一直关闭,整个同步过程停止,这种我称为撑死;阀门2故障的表现是在已关闭的情况下,二级缓冲区未满时不能正常打开,二级缓冲区数据全部被取光后整个同步过程停止,这种我称为饿死。