到现在我发现我们突然给扯远了,我们再回到init.cpp中的AppInit2的函数。我们看第七步:load block chain 加载块链
这部分内容也很多。我们分段来看:
这部分代码是在加载区块链之前先建了个blocks的区块文件夹。这外文件夹就是存储区块数据的地方,然后把这个文件夹创建了9999个硬链接。关于什么叫硬链接我们看下百度百科的说明:
硬链接概念
一个文件有几个文件名(用ln命令实现多个文件名),我们就说该文件的链接数为几。由定义可知,此链接数可以是1, 这表明该文件只有一个文件名。
总之,硬链接就是让多个不在或者同在一个目录下的文件名,同时能够修改同一个文件,其中一个修改后,所有与其有硬链接的文件都一起修改了。
我们看下这个函数的说明:
void create_hard_link(conststd::filesystem::path&target,constpath&std::filesystem::link);
link与target就是指代同一文件的二个逻辑名(它们等价)。即使原名target被删除,文件也会继续存在,并可以link访问。
所以创建硬链接还有个好处,就是防止误删,创建了这么多的硬链接,我估计其主要目的就是防止区块的数据会被误删。
如果硬链接创建成功,则 fReindex = true; 表示重新对区块数据索引。
下面的代码是计算各种数据的缓存大小,我们先看下txdb.h中关于dbCache(数据库缓存)的常量定义:
这部分代码对数据库的缓存大小进行了边界处理。关于最大缓存大小和最小缓存大小是一个常量。可以看到默认的缓存大小是100兆,最大的缓存是根据编译器来决定的。如果编译器大于4byte,则最大是4096兆,否则是1024兆。最小缓存是4兆。
这部分代码对总缓存大小和区块中的不同缓存大小进行了边界判断和设置。还对并对默克树和coinDB,nCoinCacheSize大小进行了设置。其中nCoinDBCache是总缓存大小的一半,nCoinCacheSize要是300bytes的整数倍。所以最后用300整除了一下,具体内容我们继续往下看。
这部分代码主要是谳用LoadBlockIndex()来加载了区块数据,并创建了三个对象(CBlockTreeDB,CCoinsViewDB,CCoinsViewCache)。
CBlockTreeDB :用于处理区块的数据库,这个类定义在txdb.h中。
可以看到这个类是继承于CLevelDbWrapper类的。而这个类封装的就是就是LevelDB的操作。这个LevelDB就是存储我们比特币所有区块的地方,也就是我们常说的数据库。我们看下百度百科怎么说的:
Leveldb:是一个google实现的非常高效的kv数据库,目前的版本1.2能够支持billion级别的数据量了。 在这个数量级别下还有着非常高的性能,主要归功于它的良好的设计。
KV数据库:使用键值(Key-Value)存储数据库,这是一种NoSQL(非关系型数据库)模型,其数据按照键值对的形式进行组织、索引和存储。
所以我们知道了比特币采用的数据库就是LevelDB,然后由CLevelDBWrapper类进行了封装定义在leveldbwrapper.h中,但是我们们的数据是由CBlockTreeDB进行操作。
CCoinsViewDB:
这个类定义在txdb.h中,通过代码可以看到是对ClevelDBWrapper类对象的操作,而且是继承自CCoinsView的类。所以也有了CCoinsView的操作。而CCoinsView就是对我们所拥有多少比特币的操作。
可以看到这个类中的函数都是虚函数。所以这些函数的操作都在CCoinsViewDB中进行实现了。而且CCoins就是我们的UTXO(未花费的交易输出 )的封装。
而我们最关心的是如何计算的我们的余额(我有多少比特币)也就是有多少UTXO的值。现在我们就看一下这部分代码的真容吧,这个函数就是GetStats(CCoinsStats &stats);
我们看最后一个类CCoinsViewCache:
通过代码和注释可以看出来这个类是一个缓存类。cacheCoins是用于存储缓存数据的;hashBlock是用于存储区块哈希值的;这个类的的使用估计在以后的阅读代码中会看到。
现在我们知道我们的比特币余额是怎样计算的。和UTXO对象在比特币源码中的就是一个CCoins对象。并且我们的区块数据和交易数据都是存在LevelDB中,通过CCoinsViewDB对数据库的操作来进行我们的区块和交易数据的存储和记录。
我们现在对第七步的解读也差不多了,具体的代码大家可以在相应的类中进行仔细的阅读。我们在下篇直接阅读第八步的代码。
作者:区块链研习社比特币源码研读班,black