比特币源码解读之区块确认 区块链 技术 转载

校长 一路有你 1月前 91

比特币源码解读之区块确认


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

本文主要描述矿工挖到区块或者收到“block”消息后进行的区块处理。主要包含区块有效性检查,孤立区块处理以及当前区块处理等(ps:本文暂不涉及工作量证明以及共识, 这两方面内容再后续文章中介绍)
流程图如下所示:

本文主要描述bool ProcessBlock(CNode pfrom, CBlock pblock)函数的功能。

区块重复性检查

区块是否在区块链中,如果在则返回失败


  1. uint256 hash = GetHash();
  2. if (mapBlockIndex.count(hash))
  3.    return error("AcceptBlock() : block already in mapBlockIndex");

区块是否在孤立区块中,如果在则返回失败


  1. if (mapOrphanBlocks.count(hash))
  2.    return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,14).c_str());

区块基本检查


  1. if (!pblock->CheckBlock())
  2. {
  3.    delete pblock;
  4.    return error("ProcessBlock() : CheckBlock FAILED");
  5. }

检查区块大小、时间戳


  1. // Size limits
  2. if (vtx.empty() || vtx.size() > MAX_SIZE || ::GetSerializeSize(*this, SER_DISK) > MAX_SIZE)
  3.    return error("CheckBlock() : size limits failed");
  4. // Check timestamp
  5. if (nTime > GetAdjustedTime() + 2 * 60 * 60)
  6.    return error("CheckBlock() : block timestamp too far in the future");

检查交易、PoW和MerkleRoot


  1. // First transaction must be coinbase, the rest must not be
  2. if (vtx.empty() || !vtx[0].IsCoinBase())
  3.    return error("CheckBlock() : first tx is not coinbase");
  4. for (int i = 1; i < vtx.size(); i++)
  5.    if (vtx[i].IsCoinBase())
  6.        return error("CheckBlock() : more than one coinbase");
  7. // Check transactions
  8. foreach(const CTransaction& tx, vtx)
  9.    if (!tx.CheckTransaction())
  10.        return error("CheckBlock() : CheckTransaction failed");
  11. // Check proof of work matches claimed amount
  12. if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
  13.    return error("CheckBlock() : nBits below minimum work");
  14. if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
  15.    return error("CheckBlock() : hash doesn't match nBits");
  16. // Check merkleroot
  17. if (hashMerkleRoot != BuildMerkleTree())
  18.    return error("CheckBlock() : hashMerkleRoot mismatch");

根据区块前一区块进行处理

如果前一区块不存在区块链中,则将前一区块加入孤立区块

此种情况,表示区块链出现分叉或者网络延迟导致的,则需要发送“getblocks”获取最长链中缺少的区块信息。


  1. if (!mapBlockIndex.count(pblock->hashPrevBlock))
  2. {
  3.    printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,14).c_str());
  4.    mapOrphanBlocks.insert(make_pair(hash, pblock));
  5.    mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));
  6.    // Ask this guy to fill in what we're missing
  7.    if (pfrom)
  8.        pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(pblock));
  9.    return true;
  10. }

如果前一区块不存在区块链中,则尝试接受区块


  1. if (!pblock->AcceptBlock())
  2. {
  3.    delete pblock;
  4.    return error("ProcessBlock() : AcceptBlock FAILED");
  5. }
  6. delete pblock;

接受区块

“接受区块”包含区块重复性检查,前一区块有效性区块,时间戳检查,工作量证明;当这些条件检查通过后,将区块写入磁盘并加入到区块链中。(加入到区块链具体在后续“比特币源码解读之共识”一文中介绍)


  1. bool CBlock::AcceptBlock()
  2. {
  3.    // Check for duplicate
  4.    uint256 hash = GetHash();
  5.    if (mapBlockIndex.count(hash))    // 当前区块重复性检查
  6.        return error("AcceptBlock() : block already in mapBlockIndex");
  7.    // Get prev block index
  8.    map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
  9.    if (mi == mapBlockIndex.end())   // 前一区块有效性检查
  10.        return error("AcceptBlock() : prev block not found");
  11.    CBlockIndex* pindexPrev = (*mi).second;
  12.    // Check timestamp against prev
  13.    if (nTime <= pindexPrev->GetMedianTimePast())   // 时间戳检查
  14.        return error("AcceptBlock() : block's timestamp is too early");
  15.    // Check proof of work
  16.    if (nBits != GetNextWorkRequired(pindexPrev))    // 工作量检查
  17.        return error("AcceptBlock() : incorrect proof of work");
  18.    // Write block to history file
  19.    unsigned int nFile;
  20.    unsigned int nBlockPos;
  21.    if (!WriteToDisk(!fClient, nFile, nBlockPos))    // 区块写入磁盘中
  22.        return error("AcceptBlock() : WriteToDisk failed");
  23.    if (!AddToBlockIndex(nFile, nBlockPos))    // 加入到区块链中
  24.        return error("AcceptBlock() : AddToBlockIndex failed");
  25.    if (hashBestChain == hash)      // 如果该区块链式最长链,则广播消息
  26.        RelayInventory(CInv(MSG_BLOCK, hash));
  27.    return true;
  28. }

处理孤立区块和当前区块的关系,并尝试接受孤立区块


  1. vector<uint256> vWorkQueue;
  2. vWorkQueue.push_back(hash);
  3. for (int i = 0; i < vWorkQueue.size(); i++)
  4. {
  5.    uint256 hashPrev = vWorkQueue[i];
  6.    for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
  7.         mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
  8.         ++mi)
  9.    {
  10.        CBlock* pblockOrphan = (*mi).second;
  11.        if (pblockOrphan->AcceptBlock())   // 尝试接受孤立区块
  12.            vWorkQueue.push_back(pblockOrphan->GetHash());
  13.        mapOrphanBlocks.erase(pblockOrphan->GetHash());
  14.        delete pblockOrphan;
  15.    }
  16.    mapOrphanBlocksByPrev.erase(hashPrev);
  17. }

上一篇: 比特币源码解读之选币

下一篇:比特币源码解读之工作量证明

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

作者:雨后的蚊子

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

帖子版权声明 1、本帖标题:比特币源码解读之区块确认
    本站网址:https://bbs.ifc123.net/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:ifc@1e9.cc 除非注明,本帖由一路有你在本站《专家专栏》版块原创发布, 转载请注明出处!
最新回复 (1)
返回