比特币源码解读之创世块的产生

(本文使用的是比特币v0.1.0版本 点击下载源码)

  • 加载区块索引
  • 判断区块索引是否为空
  • 初始化时间戳和交易
  • 初始化区块
  • HASH校验
  • 区块写入磁盘中
  • 增加区块索引

本文主要描述创世块是如何产生的,接着之前的文章《比特币源码解读之初始化》中初始化加载模块进行描述,本文主要描述创世块时间戳、创币奖励、区块信息的初始化,以及区块的存储以及区块索引的生成。
流程图如下所示:

加载区块索引

 
  
  1. if (!LoadBlockIndex())
  2. strErrors += "Error loading blkindex.dat\n";
  3. bool LoadBlockIndex(bool fAllowNew)
  4. {
  5. //
  6. // Load block index
  7. //
  8. CTxDB txdb("cr");
  9. if (!txdb.LoadBlockIndex())
  10. return false;
  11. txdb.Close();
  12. ....
  13. }

判断区块索引是否为空

 
  
  1. // Init with genesis block
  2. //
  3. if (mapBlockIndex.empty())
  4. {
  5. if (!fAllowNew)
  6. return false;
  7. ...
  8. }

初始化时间戳和交易

(1)时间戳为”The Times 03/Jan/2009 Chancellor on brink of second bailout for banks” ,这句话正是泰晤士报当天的头版文章标题“2009年1月3日,财政大臣正站在第二轮救助银行业的边缘”。时间戳是作为存在性证明(Proof of existence)的关键参数。
(2)创世币的奖励为50BTC,输入为空,输出公钥为

 
  
  1. // Genesis block
  2. char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
  3. CTransaction txNew;
  4. txNew.vin.resize(1);
  5. txNew.vout.resize(1);
  6. txNew.vin[0].scriptSig = CScript() << 486604799 << CBigNum(4) << vector<unsigned char>((unsigned char*)pszTimestamp, (unsigned char*)pszTimestamp + strlen(pszTimestamp));
  7. txNew.vout[0].nValue = 50 * COIN;
  8. txNew.vout[0].scriptPubKey = CScript() << CBigNum("0x5F1DF16B2B704C8A578D0BBAF74D385CDE12C11EE50455F3C438EF4C3FBCF649B6DE611FEAE06279A60939E028A8D65C10B73071A6F16719274855FEB0FD8A6704") << OP_CHECKSIG;

初始化区块

 
  
  1. CBlock block;
  2. block.vtx.push_back(txNew);
  3. block.hashPrevBlock = 0; 前一区块为0
  4. block.hashMerkleRoot = block.BuildMerkleTree(); 计算交易的Merkle
  5. block.nVersion = 1; 版本号为1
  6. block.nTime = 1231006505; 北京时间为2009/1/4 2:15:5
  7. block.nBits = 0x1d00ffff; 记录本区块难度
  8. block.nNonce = 2083236893; 随机数

其中nNonce 的值设定使得该块的hash是以一串0开头的。对于块数据的一点点改变(比如nonce)都会引起block hash的巨大变化。由于逆向预测hash值相对应的一组bit值(hash原文)是不可行的,在尝试足够多的nonce值且计算每个nonce值相对应的block hash之后可以找到一个满足有指定数量 0 bits (0比特位) 的hash值。

HASH校验

校验交易的Merkle值和区块Hash

 
  
  1. assert(block.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
  2. assert(block.GetHash() == hashGenesisBlock);

区块写入磁盘中

文件名为blk0001.dat,后续区块名字递增,如blk0002.dat …

 
  
  1. unsigned int nFile;
  2. unsigned int nBlockPos;
  3. if (!block.WriteToDisk(!fClient, nFile, nBlockPos))
  4. return error("LoadBlockIndex() : writing genesis block to disk failed");
  5. bool WriteToDisk(bool fWriteTransactions, unsigned int& nFileRet, unsigned int& nBlockPosRet)
  6. {
  7. // Open history file to append
  8. CAutoFile fileout = AppendBlockFile(nFileRet);
  9. if (!fileout)
  10. return error("CBlock::WriteToDisk() : AppendBlockFile failed");
  11. if (!fWriteTransactions)
  12. fileout.nType |= SER_BLOCKHEADERONLY;
  13. // Write index header
  14. unsigned int nSize = fileout.GetSerializeSize(*this);
  15. fileout << FLATDATA(pchMessageStart) << nSize;
  16. // Write block
  17. nBlockPosRet = ftell(fileout);
  18. if (nBlockPosRet == -1)
  19. return error("CBlock::WriteToDisk() : ftell failed");
  20. fileout << *this;
  21. return true;
  22. }

增加区块索引

 
  
  1. if (!block.AddToBlockIndex(nFile, nBlockPos))
  2. return error("LoadBlockIndex() : genesis block not accepted");

其功能包含重复性区块检查、最好分支处理、新最好分支处理等等,在后续比特币源码解读之挖矿一文中介绍

上一篇: 比特币源码解读之私钥、公钥和地址

版权声明:B链网原创,严禁修改。转载请注明作者和原文链接
http://www.360bchain.com/article/76.html

你可能感兴趣的:(区块链)