以太坊源码分析(六)-带状态的区块写入

一、BlockChain的WriteBlockWithState方法

1.1 前言

本章节介绍BlockChain的WriteBlockWithState方法。WriteBlockWithState方法的功能是将一个区块写入区块链,同时处理可能发生的分叉。能够执行到WriteBlockWithState这个函数说明区块本身是被验证过的没有问题,所以这个方法一定能将区块写入数据库,但是能不能写入规范链,需要进一步判断,假设写入的是规范链,是在原有规范链基础是追加一个呢? 还是将数据库中的一个分叉升级成规范链呢? 这个也要进一步判断。所以WriteBlockWithState方法将区块写入区块链的同时还会处理可能的分叉。

1.2 WriteBlockWithState函数

WriteBlockWithState函数将一个区块写入区块链的过程其实就是将一个区块写入数据库,前面讲BlockChain基本概念的时候提到一个区块在数据库中是几个部分单独存储的,分别是区块头、区块体、总难度、收据、区块号、状态,所以WriteBlockWithState函数就是将区块的这几个部分按特定的键值对写入数据库。

第5步是看这个区块能不能写入规范链,以太坊源码分析(四)提到一个区块能不能写入规范链得看这个区块的总难度是不是大于当前的规范链头区块的总难度,那如果两者难度相同呢,怎么办? 以太坊的做法是再由区块高度来比较,所以存在下面几种可能性以及待插入区块是否能插入规范链:

第5的reorg变量如果得出是true,表示当前区块是要写入规范链的,首先拿待插入的区块的总难度和当前规范链头区块的总难度比较, 如果待插入的更大,reorg为true, 待插入的区块必然要写入规范链,下面这段代码处理其他几种情况:

第6步, reorg为true,区块一定能写入规范链,那如何确定是将这个区块追加到当前规范链还是将原有一条分叉升级成规范链呢?就是看待插入的区块的父区块是否指向的当前规范链的头区块,如果指向了,就调用BlockChain的insert方法将待插入区块追加到当前规范链,否则调用BlockChain的reorg函数将数据库中的一个分叉链升级成规范链。

1.3 Insert方法

inert方法就是将区块写入规范链,从下面的代码可以看出将一个区块写入到规范链其实就是3步:

1.调用WriteCanonicalHash函数将数据库中‘h’ + num + ‘n’标记成待插入区块的hash。

2.调用WriteHeadBlockHash函数将数据库中“LastBlock”标记成待插入区块的hash。

3.调用bc.currentBlock.Store(block)将BlockChain的currentBlock更新成待插入区块

上面代码中updateHeads如果为true说明headerChain的延伸发生错误,由于headerChain在更新一个头区块的时候也要更新数据库中‘h’ + num + ‘n’,所以insert函数只要从数据库中读出待插入区块号在数据库中‘h’ + num + ‘n’标记的hash,是不是跟待插入区块的hash相同,如果不同,说明headerChain延伸错误,需要纠正回来,所谓的纠正就是将headerChain的头更新成BlockChain的currentBlock,也就是待插入的区块。

1.4 Reorg方法

reorg函数功能是处理区块插入时引起的分叉。也就是说待插入区块是插入规范链,但是它的父区块指向的又不是当前规范链的头区块,说明数据中的一个分叉链要升级成规范链。reorg的原理是向下追溯,找到这两条链的共同祖先区块,这个共同祖先区块就是分叉点,然后将新链(待插入区块所在的链)上从分叉点后面所有区块全部重新调用上面的insert方法更新一下规范链,这样原来的规范链就变成了一条分叉链。待插入区块所在的链变成了新的规范链。

上面的代码还涉及到一个概念叫交易查找入口(TxLookupEntry),所谓的交易查找入口就是在数据库中记录了所有规范链上区块中每一个交易的信息,信息的数据结构如下:

存储这个一个结构有很大的意义,如果你知道一个交易的hash,这个hash就能在数据库中查找有没有这个查找入口,如果没有,说明交易没有上链,如果有,就能快速确定这个交易在哪个区块中,已经在区块中的偏移。存储的数据结构包括3部分内容,这个交易所在的区块的hash(BlockHash)和区块号(BlockIndex)、交易在区块中的偏移(Index)。在数据库中存储的时候是以这个交易的hash值编码后的结果为key,这个数据结构编码后的结果为value存储的。当然只有规范链上的区块中的交易会存储,分叉链上的区块中的交易是不会存储的。所以reorg函数中在回溯老链和新链的时候会把两条链上所有的交易收集起来,然后如同第3步找出那些老链中不存在于新链的交易,将他们的TxLookupEntry从数据库中删除。

1.5 总结

本章节主要介绍WriteBlockWithState的流程,从上面的分析可以看出WriteBlockWithState函数里面主要是将一个区块写入数据库,然后判断这个区块能不能写入规范链链,如果能写则写入,同时处理分叉。

-END-

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181203G17LIL00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券