比特币源码阅读(RPC命令-getblock)
2018-08-13 本文已影响0人
坠叶飘香
1.通过hash从mapBlockIndex获得CBlockIndex
2.通过CBlockIndex得到该区块在文件中的存储位置,读取文件,获得CBlock对象
3.从CBlockIndex和CBlock获取所需要的值,封装成json对象返回
src/rpc/blockchain.cpp
static UniValue getblock(const JSONRPCRequest& request)
{
LOCK(cs_main);
std::string strHash = request.params[0].get_str(); //获得参数 hash
uint256 hash(uint256S(strHash));
int verbosity = 1;
if (!request.params[1].isNull()) {
if(request.params[1].isNum())
verbosity = request.params[1].get_int();
else
verbosity = request.params[1].get_bool() ? 1 : 0;
}
const CBlockIndex* pblockindex = LookupBlockIndex(hash); //第一步
if (!pblockindex) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
}
const CBlock block = GetBlockChecked(pblockindex); //第二步
if (verbosity <= 0)
{
CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION | RPCSerializationFlags());
ssBlock << block;
std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
return strHex;
}
return blockToJSON(block, pblockindex, verbosity >= 2); //第三步
}
第一步 通过hash从mapBlockIndex获得CBlockIndex
src/validation.h
inline CBlockIndex* LookupBlockIndex(const uint256& hash)
{
AssertLockHeld(cs_main);
BlockMap::const_iterator it = mapBlockIndex.find(hash);
return it == mapBlockIndex.end() ? nullptr : it->second;
}
第二步 通过CBlockIndex读取文件,获得CBlock对象
src/rpc/blockchain.cpp
static CBlock GetBlockChecked(const CBlockIndex* pblockindex)
{
CBlock block;
if (IsBlockPruned(pblockindex)) { //Prune 修剪
throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
}
if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
// Block not found on disk. This could be because we have the block
// header in our index but don't have the block (for example if a
// non-whitelisted node sends us an unrequested long chain of valid
// blocks, we add the headers to our index, but don't accept the
// block).
throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
}
return block;
}
从CBlockIndex构建CDiskBlockPos对象
src/validation.cpp
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
{
CDiskBlockPos blockPos;
{
LOCK(cs_main);
blockPos = pindex->GetBlockPos();
}
if (!ReadBlockFromDisk(block, blockPos, consensusParams))
return false;
if (block.GetHash() != pindex->GetBlockHash())
return error("ReadBlockFromDisk(CBlock&, CBlockIndex*): GetHash() doesn't match index for %s at %s",
pindex->ToString(), pindex->GetBlockPos().ToString());
return true;
}
从文件读取构建CBlock
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
block.SetNull();
// Open history file to read
CAutoFile filein(OpenBlockFile(pos, true), SER_DISK, CLIENT_VERSION);
if (filein.IsNull())
return error("ReadBlockFromDisk: OpenBlockFile failed for %s", pos.ToString());
// Read block
try {
filein >> block;
}
catch (const std::exception& e) {
return error("%s: Deserialize or I/O error - %s at %s", __func__, e.what(), pos.ToString());
}
// Check the header
if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) //工作量证明检测
return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
return true;
}