比特币源码解析之初始化

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

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

阅读更多

没有更多推荐了,返回首页