本文主要是介绍使用VC学习BTC:(一)了解block的存盘文件blk*.dat,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
使用VC学习BTC:(一)了解block的存盘文件blk*.dat
虽然首先使用win10的linux layer在Windows上先编译并成功运行了bitcoin core,但是对于更习惯VS开发工具的人来说,总是在VS下跟踪调试更顺手,因此准备建立一个VS工程来编译bitcoin,并逐步学习了解它的实现比特币存盘文件blkxxxx.dat格式
为了便于VS上编译运行,先从存盘的数据文件开始,这部分涉及的代码应比较容易在VS上运行起来。
工程建立步骤如下:
- 从官方开源代码库https://github.com/bitcoin/bitcoin下载源代码;
- 在下载的源代码的build-aux目录下建立vs目录;
- 在新建的vs目录下创建vs2017的工程(Solution),并添加一个windows控制台的C++项目bitcoin(Project);
- 在bitcoin项目中添加部分下载的源文件,添加后项目文件如下
- 添加一个新的CPP文件,增加LoadExternalBlockFile函数
-
#define MESSAGE_START_SIZE 4
-
unsigned char pchMessageStart[MESSAGE_START_SIZE] = { 0xf9, 0xbe, 0xb4, 0xd9 };
-
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
-
{
-
int nLoaded = 0;
-
try {
-
// This takes over fileIn and calls fclose() on it in the CBufferedFile destructor
-
CBufferedFile blkdat(fileIn, 2 * MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE + 8, SER_DISK, CLIENT_VERSION);
-
uint64_t nRewind = blkdat.GetPos();
-
while (!blkdat.eof()) {
-
blkdat.SetPos(nRewind);
-
nRewind++; // start one byte further next time, in case of failure
-
blkdat.SetLimit(); // remove former limit
-
unsigned int nSize = 0;
-
try {
-
// locate a header
-
unsigned char buf[MESSAGE_START_SIZE];
-
blkdat.FindByte(pchMessageStart[0]);
-
nRewind = blkdat.GetPos() + 1;
-
blkdat >> FLATDATA(buf);
-
if (memcmp(buf, pchMessageStart, MESSAGE_START_SIZE))
-
continue;
-
// read size
-
blkdat >> nSize;
-
if (nSize < 80 || nSize > MAX_BLOCK_SERIALIZED_SIZE)
-
continue;
-
}
-
catch (const std::exception&) {
-
// no valid block header found; don't complain
-
break;
-
}
-
try {
-
// read block
-
uint64_t nBlockPos = blkdat.GetPos();
-
if (dbp)
-
dbp->nPos = nBlockPos;
-
blkdat.SetLimit(nBlockPos + nSize);
-
blkdat.SetPos(nBlockPos);
-
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
-
CBlock& block = *pblock;
-
blkdat >> block;
-
nRewind = blkdat.GetPos();
-
printf("%s\n\n", block.ToString().c_str());
-
}
-
catch (const std::exception& e) {
-
printf("%s: Deserialize or I/O error - %s\n", __func__, e.what());
-
}
-
nLoaded++;
-
}
-
}
-
catch (const std::runtime_error& e) {
-
printf("System error: %s\n", e.what());
-
}
-
if (nLoaded > 0)
-
printf("Loaded %i blocks from external file\n", nLoaded);
-
return nLoaded > 0;
-
}
这个函数的主体内容是从比特币的验证代码部分抄的,之所以抄是因为一旦引入验证代码,整个工程会复杂很多。
- 增加main函数
-
int main(void)
-
{
-
// Todo: Change to the real path where you store the bitcoin block file
-
char path[] = "G:\\blockchain\\bitcoin\\bin\\Bitcoin\\blocks\\blk00000.dat";
-
FILE *file = fsbridge::fopen(path, "rb");
-
LoadExternalBlockFile(file, NULL);
-
return 0;
-
}
这里我偷懒了,直接写死了一个存盘的block文件路径,反正只是为了学习嘛。
到这里,工程文件都有了,但是编译还有问题,因为比特币的源代码有依赖。得益于vs集成的nuget包管理工具,可以不用自己下载依赖的源代码编译(也是累死人的工作哦,开源代码在vs下的编译都很烦)。
- 引入依赖包:
解决方案处点击鼠标右键,在弹出的菜单中选择“管理解决方案的NuGet程序包”
搜索boost_filesystem-vc141及boost_system-vc141,选择
- 修改比特币代码错误
写本文时此错误的修复已经提交,但是仍未被接受,在被接受后再下载源代码将不用修改。
- 编译运行
至此,就可以跟踪调试来看整个文件的格式了!
- 文件是由一系列的block组成的,没有额外的文件头,chain.h中定义的CBlockFileInfo类并非用于这里;
- 每个block包括:
字节数 | 内容 | 说明 |
---|---|---|
4字节 | 0xF9 0xBE 0xB4 0xD9 | 所谓的Magic,用于确认block开始 |
4字节 | Block Length Little-Endian | Little-Endian的unsigned int |
Block Length | CBlock类序列化后的数据 | CBlock类定义在block.h文件中 |
- CBlock数据包括CBlockHeader以及一些列的CTransaction数据,其中CBlockHeader包括:
字节数 | 内容 | 说明 |
---|---|---|
4字节 | 版本号 | Little-Endian的int32_t |
32字节 | 前一个block的hash值 | Little-Endian的uint256 |
32字节 | MerkleRoot | Little-Endian的uint256 |
4字节 | 时间戳 | 块生成时的网络时间 |
4字节 | 目标值 | 当前区块生成所达成目标值的特征 |
4字节 | 随机数 | 用于挖矿时生成符合要求的块哈希 |
- 在CBlockHerder之后,是交易数量及每个交易的记录
- 交易数量为紧缩格式(CompactSize)的无符号整数
紧缩格式整数的读取,在serialize.h的ReadCompactSize模板中,其规则为若第一个字节是255,则读取后续8字节作为uint64;若第一字节是254,则读取后续4字节作为uint32;若第一字节是253,则读取后续2字节作为uint16;否则将第一个字节作为uint8。
因此,这是一个可变长度的数据,最小占用1字节,最大占用9字节。
- 之后是按照交易数量来读取交易数据,实际的交易数据读取跟踪定位在transaction.h的函数inline void UnserializeTransaction(TxType& tx, Stream& s) 中,这个后面分析交易时再来分析细节。
不想自己从头建工程的,可以从csdn下载,地址为http://download.csdn.net/download/lazypiggy/10265510。
【原创首发地址:http://http://blog.csdn.net/lazypiggy/article/details/79414709,转发请保留此链接】
这篇关于使用VC学习BTC:(一)了解block的存盘文件blk*.dat的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!