Block Checking & Submit Blocks
File - main.cpp
Line - 1154 -1295
bool CBlock::CheckBlock() const
{
These are checks that are independent of context
that can be verified before saving an orphan block.
// This section checks the Size limits
if (vtx.empty() || vtx.size() > MAX_SIZE || ::GetSerializeSize(*this, SER_DISK) > MAX_SIZE)
return error("CheckBlock() : size limits failed");
// This section of code if for checking the timestamp of the block, a timestamp is valid if it is greater than the median timestamp of last 11 blocks and less than the network-adjusted time + 2 hours
if (nTime > GetAdjustedTime() + 2 * 60 * 60)
return error("CheckBlock() : block timestamp too far in the future");
// This section checks to make sure the first transaction is a coinbase transaction and everything else is not a coinbase TX
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");
// This section checks that the 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");
// It is then passed to check the merkleroot
if (hashMerkleRoot != BuildMerkleTree())
return error("CheckBlock() : hashMerkleRoot mismatch");
return true;
}
Now the code will check for AcceptBlock by checking the following aspects.
bool CBlock::AcceptBlock()
// In this section the code performs a check for duplicate block.
uint256 hash = GetHash();
if (mapBlockIndex.count(hash))
return error("AcceptBlock() : block already in mapBlockIndex");
// Here the code will get the previous block index
map::iterator mi = mapBlockIndex.find(hashPrevBlock);
if (mi == mapBlockIndex.end())
return error("AcceptBlock() : prev block not found");
CBlockIndex* pindexPrev = (*mi).second;
// It will then check the timestamp against previous block
if (nTime <= pindexPrev->GetMedianTimePast())
return error("AcceptBlock() : block's timestamp is too early");
// It then performs a check on the proof of work
if (nBits != GetNextWorkRequired(pindexPrev))
return error("AcceptBlock() : incorrect proof of work");
// Here the code will write the block to history file
if (!CheckDiskSpace(::GetSerializeSize(*this, SER_DISK)))
return error("AcceptBlock() : out of disk space");
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));
The next section is commented out of the code and I am still looking for some references for the code below and relations to VAtoms.
// // Add atoms to user reviews for coins created
// vector vchPubKey;
// if (ExtractPubKey(vtx[0].vout[0].scriptPubKey, false, vchPubKey))
// {
// unsigned short nAtom = GetRand(USHRT_MAX - 100) + 100;
// vector vAtoms(1, nAtom);
// AddAtomsAndPropagate(Hash(vchPubKey.begin(), vchPubKey.end()), vAtoms, true);
// }
return true;
}
Next the code looks to process the block by the following.
bool ProcessBlock(CNode* pfrom, CBlock* pblock)
// Check for duplicate
uint256 hash = pblock->GetHash();
if (mapBlockIndex.count(hash))
return error("ProcessBlock() : already have block %d %s", mapBlockIndex[hash]->nHeight, hash.ToString().substr(0,14).c_str());
if (mapOrphanBlocks.count(hash))
return error("ProcessBlock() : already have block (orphan) %s", hash.ToString().substr(0,14).c_str());
// Preliminary checks
if (!pblock->CheckBlock())
{
delete pblock;
return error("ProcessBlock() : CheckBlock FAILED");
}
// If don't already have its previous block, shunt it off to holding area until we get it
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;
}
// Store to disk
if (!pblock->AcceptBlock())
{
delete pblock;
return error("ProcessBlock() : AcceptBlock FAILED");
}
delete pblock;
// Recursively process any orphan blocks that depended on this one
vector vWorkQueue;
vWorkQueue.push_back(hash);
for (int i = 0; i < vWorkQueue.size(); i++)
{
uint256 hashPrev = vWorkQueue[i];
for (multimap::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);
}
At this point the miner would be very happy! as the block has passed the checked and can be called Valid.
The code then prints below :
printf("ProcessBlock: ACCEPTED\n");
return true;