比特币源码解析之初始化

转载 2018年04月17日 21:49:12

本文主要描述了进程启动时节点地址、区块信息和钱包信息的初始化(节点线程和矿工挖矿线程在后续“比特币源码解析之线程处理”一文中介绍,孤立块处理在后续“比特币源码解读之挖矿”一文中介绍)。
初始化流程图如下所示:

1 加载地址LoadAddresses()

(1)首先调用CAddrDB类的LoadAddresses()函数(同时CAddrDB的构造函数默认打开addr.dat文件)。源码如下所示:

  1. bool LoadAddresses()
  2. {
  3. return CAddrDB("cr+").LoadAddresses();
  4. }
  5. class CAddrDB : public CDB
  6. {
  7. public:
  8. CAddrDB(const char* pszMode="r+", bool fTxn=false) : CDB("addr.dat", pszMode, fTxn) { }
  9. ... ...
  10. }

(2)判断有没有用户自定义的地址信息(信息位于addr.txt中)。如果有自定义地址信息,则获取对应地址信息,如果该地址不在mapAddresses中,则保存到mapAddresses并且写入addr.dat配置文件中;否则将nServices信息写入addr.dat配置文件中。

  1. map<vector<unsigned char>, CAddress>::iterator it = mapAddresses.find(addr.GetKey());
  2. if (it == mapAddresses.end())
  3. {
  4. // New address
  5. mapAddresses.insert(make_pair(addr.GetKey(), addr));
  6. addrdb.WriteAddress(addr);
  7. return true;
  8. }
  9. else
  10. {
  11. CAddress& addrFound = (*it).second;
  12. if ((addrFound.nServices | addr.nServices) != addrFound.nServices)
  13. {
  14. // Services have been added
  15. addrFound.nServices |= addr.nServices;
  16. addrdb.WriteAddress(addrFound);
  17. return true;
  18. }
  19. }

(3)从addr.dat文件中匹配key为“addr”,从而获取对应地址信息,并插入到mapAddresses向量中。

  1. loop
  2. {
  3. // Read next record
  4. CDataStream ssKey;
  5. CDataStream ssValue;
  6. int ret = ReadAtCursor(pcursor, ssKey, ssValue);
  7. if (ret == DB_NOTFOUND)
  8. break;
  9. else if (ret != 0)
  10. return false;
  11. // Unserialize
  12. string strType;
  13. ssKey >> strType;
  14. if (strType == "addr")
  15. {
  16. CAddress addr;
  17. ssValue >> addr;
  18. mapAddresses.insert(make_pair(addr.GetKey(), addr));
  19. }
  20. }

2 加载区块LoadBlockIndex()

(1)首先调用CTxDB 类的LoadBlockIndex()函数(同时CTxDB 的构造函数默认打开blkindex.dat文件)。如果打开blkindex.dat失败,则创建创世块(创世块的后续文章介绍)。

  1. CTxDB txdb("cr");
  2. if (!txdb.LoadBlockIndex())
  3. return false;
  4. txdb.Close();
  5. class CTxDB : public CDB
  6. {
  7. public:
  8. CTxDB(const char* pszMode="r+", bool fTxn=false) : CDB(!fClient ? "blkindex.dat" : NULL, pszMode, fTxn) { }
  9. ... ...
  10. };

(3)从blkindex.dat文件中匹配字符位“blockindex”的key值,进而获取对应区块索引信息,如果mapBlockIndex中不存在该区块,则插入mapBlockIndex中向量中。

  1. loop
  2. {
  3. // Read next record
  4. CDataStream ssKey;
  5. if (fFlags == DB_SET_RANGE)
  6. ssKey << make_pair(string("blockindex"), uint256(0));
  7. CDataStream ssValue;
  8. int ret = ReadAtCursor(pcursor, ssKey, ssValue, fFlags);
  9. fFlags = DB_NEXT;
  10. if (ret == DB_NOTFOUND)
  11. break;
  12. else if (ret != 0)
  13. return false;
  14. // Unserialize
  15. string strType;
  16. ssKey >> strType;
  17. if (strType == "blockindex")
  18. {
  19. CDiskBlockIndex diskindex;
  20. ssValue >> diskindex;
  21. // Construct block index object
  22. CBlockIndex* pindexNew = InsertBlockIndex(diskindex.GetBlockHash());
  23. pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev);
  24. pindexNew->pnext = InsertBlockIndex(diskindex.hashNext);
  25. pindexNew->nFile = diskindex.nFile;
  26. pindexNew->nBlockPos = diskindex.nBlockPos;
  27. ... ...
  28. }
  29. else
  30. {
  31. break;
  32. }
  33. }

(4)如果该区块是创世块pindexGenesisBlock,则保存到创世块索引pindexGenesisBlock中

  1. if (pindexGenesisBlock == NULL && diskindex.GetBlockHash() == hashGenesisBlock)
  2. pindexGenesisBlock = pindexNew;

(5)从配置文件blkindex.dat中找到字符位“hashBestChain”的key值,取出索引保存到最长链索引pindexBest中以及取出高度保存到nBestHeight 中。

  1. if (!ReadHashBestChain(hashBestChain))
  2. {
  3. if (pindexGenesisBlock == NULL)
  4. return true;
  5. return error("CTxDB::LoadBlockIndex() : hashBestChain not found\n");
  6. }
  7. if (!mapBlockIndex.count(hashBestChain))
  8. return error("CTxDB::LoadBlockIndex() : blockindex for hashBestChain not found\n");
  9. pindexBest = mapBlockIndex[hashBestChain];
  10. nBestHeight = pindexBest->nHeight;

3加载钱包LoadWallet()

(1)调用CWalletDB类的LoadWallet()函数(同时CWalletDB的构造函数默认打开wallet.dat文件)。

  1. vector<unsigned char> vchDefaultKey;
  2. if (!CWalletDB("cr").LoadWallet(vchDefaultKey))
  3. return false;
  4. class CWalletDB : public CDB
  5. {
  6. public:
  7. CWalletDB(const char* pszMode="r+", bool fTxn=false) : CDB("wallet.dat", pszMode, fTxn) { }
  8. }

(2)从wallet.dat文件中

  • 匹配字符为“defaultkey”的key,从而获取对应默认钱包地址.
    1. if (strType == "defaultkey")
    2. {
    3. ssValue >> vchDefaultKeyRet;
    4. }
  • 匹配字符为“name”的key,从而获取对应新增的公钥和私钥地址,并将名称和地址信息保存到向量mapAddressBook中。
    1. if (strType == "name")
    2. {
    3. string strAddress;
    4. ssKey >> strAddress;
    5. ssValue >> mapAddressBook[strAddress];
    6. }
  • 匹配字符为“key”的key,从而获取对应新增的公钥和私钥地址,将私钥保存在mapKeys[vchPubKey]中,将公钥保存在mapPubKeys[Hash160(vchPubKey)]中。

    1. if (strType == "key")
    2. {
    3. vector<unsigned char> vchPubKey;
    4. ssKey >> vchPubKey;
    5. CPrivKey vchPrivKey;
    6. ssValue >> vchPrivKey;
    7. mapKeys[vchPubKey] = vchPrivKey;
    8. mapPubKeys[Hash160(vchPubKey)] = vchPubKey;
    9. }
  • 匹配字符为“tx”的key,从而获取对应交易的信息,并将交易信息保存到向量mapWallet中。

    1. if (strType == "tx")
    2. {
    3. uint256 hash;
    4. ssKey >> hash;
    5. CWalletTx& wtx = mapWallet[hash];
    6. ssValue >> wtx;
    7. if (wtx.GetHash() != hash)
    8. printf("Error in wallet.dat, hash mismatch\n");
    9. }

    (3)判断默认的vchDefaultKey是否在mapKeys中,如果在,则对应的公钥和私钥保存在keyUser结构中。否则创建一个新的keyUser, 并以名称为“Your Address”保存到向量向量mapAddressBook中;同时写入配置文件wallet.dat中。

    1. if (mapKeys.count(vchDefaultKey))
    2. {
    3. // Set keyUser
    4. keyUser.SetPubKey(vchDefaultKey);
    5. keyUser.SetPrivKey(mapKeys[vchDefaultKey]);
    6. }
    7. else
    8. {
    9. // Create new keyUser and set as default key
    10. keyUser.MakeNewKey();
    11. if (!AddKey(keyUser))
    12. return false;
    13. if (!SetAddressBookName(PubKeyToAddress(keyUser.GetPubKey()), "Your Address"))
    14. return false;
    15. CWalletDB().WriteDefaultKey(keyUser.GetPubKey());
    16. }

上一篇:
比特币源码解读之整体框架

版权声明:B链网原创,严禁修改。转载请注明作者和原文链接

作者:雨后的蚊子

原文链接 http://www.360bchain.com/article/41.html

比特币源码解析(1) - 整体框架

比特币源码解析(1) - 整体框架0x00 写在前面研究了这么久的区块链却一直都没有完整的看过一个区块链项目的代码,甚至还一度沉迷各种ICO,每天看着各种货币层出不穷,跌跌涨涨,起起伏伏,不亦乐乎。现...
  • u012183589
  • u012183589
  • 2017-08-27 21:26:14
  • 15749

比特币源码解析(2) - 准备知识 - Boost

0x00 简介Boost是一个开源、跨平台、功能强大的c++库,并且是除了stl外最常用的库,实现了很多基本操作,能让开发变得更加简单、快捷。下面我们就介绍bitcoin源码中主要用到的一些类,官方文...
  • u012183589
  • u012183589
  • 2017-08-29 11:28:52
  • 9025

一:比特币源码分析(整体源码架构)

比特币刚出来的时候大家都认为骗SB的,我TM也这么认为,啪啪啪打脸,我错了。。。。最近同学又和我谈起ICO相关投资,汗说起来都是泪,最近的火爆程度,大家可以去招聘网站上搜索区块链的相关职位等。 目前...
  • hahabeibei123456789
  • hahabeibei123456789
  • 2018-02-02 18:49:49
  • 320

比特币源码解析(21) - 可执行程序 - Bitcoind

0x00 摘要经过前面20章的分析,我们已经渐渐接近比特币的核心功能部分了,也就是它的共识、交易处理等等。虽然前面基本上都是做的一些初始化的工作,但是这些工作对于比特币的整体运行来说都是必不可缺的,并...
  • u012183589
  • u012183589
  • 2017-11-12 22:49:37
  • 2204

比特币源码学习笔记(一)

前言 从事区块链的开发,不了解其底层核心技术是不够的。许多人在看了比特币白皮书之后仍然不清楚比特币是怎样实现的,因为比特币的源码设计精巧,有许多设计白皮书未曾提及,加上本身比特币的文档稀少,加大了新手...
  • g2com
  • g2com
  • 2017-03-21 05:03:58
  • 7333

比特币源码解析(11) - 可执行程序 - Bitcoind

0x01 AppInit - Continue对于AppInit中剩下的一部分代码,我们首先浏览一下主要实现的功能,然后再具体介绍每个函数的实现方法。// src/bitcoind.cpp line ...
  • u012183589
  • u012183589
  • 2017-09-08 19:46:10
  • 2935

比特币源码解析(3) - 准备知识 - Boost

Boost中Test模块是用来给代码做单元测试的,测试的方法是白盒测试,所以编写测试必须对待测试的模块有深度的理解,然后再对正常功能和可能会出现的问题进行测试,测试的实际过程就是给定输入判定是否和预期...
  • u012183589
  • u012183589
  • 2017-08-29 22:16:54
  • 5503

比特币源码解析(7) - 数据结构 - 区块

区块是区块链的组成基本结构,也是交易信息的载体,矿工通过挖矿的形式来产生新的区块并获得奖励,新块产生的过程也是一个交易打包的过程,只有加入到区块中的交易才会被系统所有其他节点所认可,才是有效的。...
  • u012183589
  • u012183589
  • 2017-09-01 19:47:41
  • 4583

比特币源码解析(9) - 可执行程序 - Bitcoind

我使用的是Ubuntu 16.04 系统所以直接按照https://github.com/bitcoin/bitcoin/blob/master/doc/build-unix.md 编译就可以成功,编...
  • u012183589
  • u012183589
  • 2017-09-03 16:54:51
  • 7583

比特币源码解析(5) - 数据结构 - 交易

交易(transaction)是比特币甚至所有区块链中最核心的数据结构之一,可以说其他所有的模块都是为交易服务的,包括交易的产生、广播、共识、存储等等,所以我们首先从交易出发,然后逐步延伸到其他的部分...
  • u012183589
  • u012183589
  • 2017-09-01 12:01:44
  • 6323
收藏助手
不良信息举报
您举报文章:比特币源码解析之初始化
举报原因:
原因补充:

(最多只允许输入30个字)