主页 > imtoken钱包下载2.0 > 用VC学习BTC:(1)了解区块的保存文件blk*.dat
用VC学习BTC:(1)了解区块的保存文件blk*.dat
用VC学习BTC:(1)了解区块的保存文件blk*.dat
虽然先用win10的linux层在Windows上编译并成功运行了bitcoin core,但是对于比较习惯VS开发工具的人来说,在VS下跟踪调试总是比较容易的,所以我准备建一个VS工程编译比特币,逐步学习理解其实现比特币存储文件blkxxxx.dat格式
为了方便在VS上编译运行,先从保存的数据文件开始。 这部分涉及的代码在VS上应该是比较容易跑起来的。
创建项目的步骤如下:
#define MESSAGE_START_SIZE 4
unsigned char pchMessageStart[MESSAGE_START_SIZE] = { 0xf9, 0xbe, 0xb4, 0xd9 };
bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
{
int nLoaded = 0;
尝试 {
// 这会接管 fileIn 并在 CBufferedFile 析构函数中对其调用 fclose()
CBufferedFile blkdat(fileIn, 2 * MAX_BLOCK_SERIALIZED_SIZE, MAX_BLOCK_SERIALIZED_SIZE + 8, SER_DISK, CLIENT_VERSION);
uint64_t nRewind = blkdat。 获取位置();
while (!blkdat.eof()) {
块数据。 设置位置(nRewind);
nRewind++; // 下次再开始一个字节,以防失败
blkdat.SetLimit(); // 移除之前的限制
无符号整数 nSize = 0;
尝试 {
//定位一个header
无符号字符缓冲区[MESSAGE_START_SIZE];
blkdat.FindByte(pchMessageStart[0]);
nRewind = blkdat. 获取位置() + 1;
blkdat >> FLATDATA(buf);
如果 (memcmp(buf, pchMessageStart, MESSAGE_START_SIZE))
继续;
//读取大小
blkdat >> nSize;
如果(nSize < 80 || nSize > MAX_BLOCK_SERIALIZED_SIZE)
继续;
}
赶上(常量 std::exception&){
// 没有找到有效的区块头; 不要抱怨
休息;
}
尝试 {
// 读取块
uint64_t nBlockPos = blkdat。 获取位置();
如果(dbp)
dbp->nPos = nBlockPos;
块数据。 设置限制(nBlockPos + nSize);
块数据。 SetPos(nBlockPos);
std::shared_ptr pblock = std::make_shared();
CBlock&块 = *pblock;
blkdat >> 块;
nRewind = blkdat. 获取位置();
printf("%s\n\n", block.ToString().c_str());
}
赶上(常量 std::exception& e){
printf("%s: 反序列化或 I/O 错误 - %s\n", __func__, e.what());
}
n加载++;
}
}
捕捉(常量 std::runtime_error& e){
printf("系统错误: %s\n", e.what());
}
如果(nLoaded > 0)
printf("从外部文件加载 %i 个块\n", nLoaded);
返回 nLoaded > 0;
}
该函数的主要内容是从比特币的验证码部分复制过来的。 之所以复制比特币dat文件下载,是因为一旦引入验证码,整个工程就会复杂很多。
int 主要(无效)
{
// Todo: 更改为存储比特币块文件的真实路径
char path[] = "G:\\blockchain\\bitcoin\\bin\\Bitcoin\\blocks\\blk00000.dat";
FILE *file = fsbridge::fopen(path, "rb");
LoadExternalBlockFile(文件,NULL);
返回 0;
}
这里我偷懒了,直接写了一个保存的block文件的路径,反正就是学习用。
至此,项目文件都已经有了,但是编译还是有问题,因为比特币的源码有依赖。 得益于VS自带的nuget包管理工具比特币dat文件下载,不用自己去下载依赖源码编译了(也是个累人的活,VS下开源代码的编译很烦人)。
右键单击解决方案,然后在弹出菜单中选择“管理解决方案的 NuGet 包”
搜索boost_filesystem-vc141和boost_system-vc141,选择
在撰写本文时已提交此错误的修复程序,但尚未被接受,之后将不加修改地下载源代码。
此时可以跟踪调试查看整个文件的格式!
内容字节数说明
4字节
0xF9 0xBE 0xB4 0xD9
所谓Magic,用于确认区块的开始
4字节
块长度 Little-Endian
小端 unsigned int
区块长度
CBlock 类序列化的数据
CBlock 类在 block.h 文件中定义
内容字节数说明
4字节
版本号
小端 int32_t
32字节
前一个区块的哈希值
小端 uint256
32字节
默克尔根
小端 uint256
4字节
时间戳
区块生成的网络时间
4字节
目标价值
当前区块生成所达到的目标值的特征
4字节
随机数
用于挖矿时生成符合要求的区块哈希
对于紧凑格式整数的读取,在serialize.h的ReadCompactSize模板中,规则是如果第一个字节是255,则读取后面的8个字节为uint64; 如果第一个字节是 254,则读取后续 4 个字节为 uint32; 如果第一个字节是 253,则读取接下来的 2 个字节作为 uint16; 否则,使用第一个字节作为 uint8。
因此,这是一个变长数据,最少占用1个字节,最多占用9个字节。
如果你不想从头开始构建项目,你可以从 csdn 下载它。
【原文首发地址://blog.csdn.net/lazypiggy/article/details/79414709,转载请保留此链接】