比特币源码解读之区块确认
(本文使用的是比特币v0.1.0版本 点击下载源码)
本文主要描述矿工挖到区块或者收到“block”消息后进行的区块处理。主要包含区块有效性检查,孤立区块处理以及当前区块处理等(ps:本文暂不涉及工作量证明以及共识, 这两方面内容再后续文章中介绍)
流程图如下所示:
本文主要描述bool ProcessBlock(CNode pfrom, CBlock pblock)函数的功能。
区块重复性检查
区块是否在区块链中,如果在则返回失败
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
return error("AcceptBlock() : block already in mapBlockIndex");
区块是否在孤立区块中,如果在则返回失败
if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,14).c_str());
区块基本检查
if (!pblock->CheckBlock())
{
delete pblock;
return error("ProcessBlock() : CheckBlock FAILED");
}
检查区块大小、时间戳
// Size limits
if (vtx.empty() || vtx.size() > MAX_SIZE || ::GetSerializeSize(*this, SER_DISK) > MAX_SIZE)
return error("CheckBlock() : size limits failed");
// Check timestamp
if (nTime > GetAdjustedTime() + 2 * 60 * 60)
return error("CheckBlock() : block timestamp too far in the future");
检查交易、PoW和MerkleRoot
// First transaction must be coinbase, the rest must not be
if (vtx.empty() || !vtx[0].IsCoinBase())
return error("CheckBlock() : first tx is not coinbase");
for (int i = 1; i < vtx.size(); i++)
if (vtx[i].IsCoinBase())
return error("CheckBlock() : more than one coinbase");
// Check transactions
foreach(const CTransaction& tx, vtx)
if (!tx.CheckTransaction())
return error("CheckBlock() : CheckTransaction failed");
// Check proof of work matches claimed amount
if (CBigNum().SetCompact(nBits) > bnProofOfWorkLimit)
return error("CheckBlock() : nBits below minimum work");
if (GetHash() > CBigNum().SetCompact(nBits).getuint256())
return error("CheckBlock() : hash doesn't match nBits");
// Check merkleroot
if (hashMerkleRoot != BuildMerkleTree())
return error("CheckBlock() : hashMerkleRoot mismatch");
根据区块前一区块进行处理
如果前一区块不存在区块链中,则将前一区块加入孤立区块
此种情况,表示区块链出现分叉或者网络延迟导致的,则需要发送“getblocks”获取最长链中缺少的区块信息。
if (!mapBlockIndex.count(pblock->hashPrevBlock))
{
printf("ProcessBlock: ORPHAN BLOCK, prev=%s\n", pblock->hashPrevBlock.ToString().substr(0,14).c_str());
mapOrphanBlocks.insert(make_pair(hash, pblock));
mapOrphanBlocksByPrev.insert(make_pair(pblock->hashPrevBlock, pblock));
// Ask this guy to fill in what we're missing
if (pfrom)
pfrom->PushMessage("getblocks", CBlockLocator(pindexBest), GetOrphanRoot(pblock));
return true;
}
如果前一区块不存在区块链中,则尝试接受区块
if (!pblock->AcceptBlock())
{
delete pblock;
return error("ProcessBlock() : AcceptBlock FAILED");
}
delete pblock;
接受区块
“接受区块”包含区块重复性检查,前一区块有效性区块,时间戳检查,工作量证明;当这些条件检查通过后,将区块写入磁盘并加入到区块链中。(加入到区块链具体在后续“比特币源码解读之共识”一文中介绍)
bool CBlock::AcceptBlock()
{
// Check for duplicate
uint256 hash = GetHash();
if (mapBlockIndex.count(hash)) // 当前区块重复性检查
return error("AcceptBlock() : block already in mapBlockIndex");
// Get prev block index
map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end()) // 前一区块有效性检查
return error("AcceptBlock() : prev block not found");
CBlockIndex* pindexPrev = (*mi).second;
// Check timestamp against prev
if (nTime <= pindexPrev->GetMedianTimePast()) // 时间戳检查
return error("AcceptBlock() : block's timestamp is too early");
// Check proof of work
if (nBits != GetNextWorkRequired(pindexPrev)) // 工作量检查
return error("AcceptBlock() : incorrect proof of work");
// Write block to history file
unsigned int nFile;
unsigned int nBlockPos;
if (!WriteToDisk(!fClient, nFile, nBlockPos)) // 区块写入磁盘中
return error("AcceptBlock() : WriteToDisk failed");
if (!AddToBlockIndex(nFile, nBlockPos)) // 加入到区块链中
return error("AcceptBlock() : AddToBlockIndex failed");
if (hashBestChain == hash) // 如果该区块链式最长链,则广播消息
RelayInventory(CInv(MSG_BLOCK, hash));
return true;
}
处理孤立区块和当前区块的关系,并尝试接受孤立区块
vector<uint256> vWorkQueue;
vWorkQueue.push_back(hash);
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap<uint256, CBlock*>::iterator mi = mapOrphanBlocksByPrev.lower_bound(hashPrev);
mi != mapOrphanBlocksByPrev.upper_bound(hashPrev);
++mi)
{
CBlock* pblockOrphan = (*mi).second;
if (pblockOrphan->AcceptBlock()) // 尝试接受孤立区块
vWorkQueue.push_back(pblockOrphan->GetHash());
mapOrphanBlocks.erase(pblockOrphan->GetHash());
delete pblockOrphan;
}
mapOrphanBlocksByPrev.erase(hashPrev);
}
上一篇: 比特币源码解读之选币
下一篇:比特币源码解读之工作量证明
版权声明:B链网原创,严禁修改。转载请注明作者和原文链接
作者:雨后的蚊子