$ bitcoin-cli help getblockheader
getblockheader "hash" ( verbose )

若 verbose 为 false,返回一个序列化的字符串,区块头 'hash' 的 16 进制编码数据。
若 verbose 为 true,返回一个包含区块头  信息的对象。

参数:
1. "hash" (字符串,必备)区块哈希
2. verbose(布尔型,可选,默认为 true)true 为一个 json 对象,false 为 16 进制编码的数据

结果(verbose 为 true):
{
  "hash" : "hash",      (字符串)区块哈希(和提供的一样)
  "confirmations" : n,  (数字)确认数,若区块不在主链上则为 -1
  "height" : n,         (数字)区块高度或索引
  "version" : n,        (数字)区块版本
  "merkleroot" : "xxxx",(字符串)默克尔树根
  "time" : ttt,         (数字)从格林尼治时间(1970-01-01 00:00:00)开始以秒为单位的区块时间
  "mediantime" : ttt,   (数字)从格林尼治时间(1970-01-01 00:00:00)开始以秒为单位的中间区块时间
  "nonce" : n,          (数字)随机数
  "bits" : "1d00ffff",  (字符串)难度对应值
  "difficulty" : x.xxx, (数字)难度
  "previousblockhash" : "hash",(字符串)上一个区块的哈希
  "nextblockhash" : "hash",    (字符串)下一个区块的哈希
  "chainwork" : "0000...1f3"   (字符串)预计生成当前链所需的哈希次数(16 进制)
}

结果(verbose 为 false):
"data"(字符串)一个序列化的字符串,区块 'hash' 的 16 进制编码数据。

例子:
> bitcoin-cli getblockheader 00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09
> curl --user myusername:mypassword --data-binary '{"jsonrpc": "1.0", "id":"curltest", "method": "getblockheader", "params": ["00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09"] }' -H 'content-type: text/plain;' http://127.0.0.1:8332/
</pre>

## 源码剖析

`getblockheader` 对应的函数在文件 `rpcserver.h` 中被引用。

```cpp
extern UniValue getblockheader(const UniValue& params, bool fHelp);
```

实现在文件 `rpcblockchain.cpp` 中。

```cpp
UniValue getblockheader(const UniValue& params, bool fHelp)
{
    if (fHelp || params.size() < 1 || params.size() > 2)
        throw runtime_error(
            "getblockheader \"hash\" ( verbose )\n"
            "\nIf verbose is false, returns a string that is serialized, hex-encoded data for blockheader 'hash'.\n"
            "If verbose is true, returns an Object with information about blockheader .\n"
            "\nArguments:\n"
            "1. \"hash\"          (string, required) The block hash\n"
            "2. verbose           (boolean, optional, default=true) true for a json object, false for the hex encoded data\n"
            "\nResult (for verbose = true):\n"
            "{\n"
            "  \"hash\" : \"hash\",     (string) the block hash (same as provided)\n"
            "  \"confirmations\" : n,   (numeric) The number of confirmations, or -1 if the block is not on the main chain\n"
            "  \"height\" : n,          (numeric) The block height or index\n"
            "  \"version\" : n,         (numeric) The block version\n"
            "  \"merkleroot\" : \"xxxx\", (string) The merkle root\n"
            "  \"time\" : ttt,          (numeric) The block time in seconds since epoch (Jan 1 1970 GMT)\n"
            "  \"mediantime\" : ttt,    (numeric) The median block time in seconds since epoch (Jan 1 1970 GMT)\n"
            "  \"nonce\" : n,           (numeric) The nonce\n"
            "  \"bits\" : \"1d00ffff\", (string) The bits\n"
            "  \"difficulty\" : x.xxx,  (numeric) The difficulty\n"
            "  \"previousblockhash\" : \"hash\",  (string) The hash of the previous block\n"
            "  \"nextblockhash\" : \"hash\",      (string) The hash of the next block\n"
            "  \"chainwork\" : \"0000...1f3\"     (string) Expected number of hashes required to produce the current chain (in hex)\n"
            "}\n"
            "\nResult (for verbose=false):\n"
            "\"data\"             (string) A string that is serialized, hex-encoded data for block 'hash'.\n"
            "\nExamples:\n"
            + HelpExampleCli("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
            + HelpExampleRpc("getblockheader", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
        ); // 1. 帮助内容

    LOCK(cs_main);

    std::string strHash = params[0].get_str();
    uint256 hash(uint256S(strHash));

    bool fVerbose = true;
    if (params.size() > 1)
        fVerbose = params[1].get_bool();

    if (mapBlockIndex.count(hash) == 0) // 2. 检查区块是否存在
        throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");

    CBlockIndex* pblockindex = mapBlockIndex[hash];

    if (!fVerbose) // 3. 序列化区块头并返回
    {
        CDataStream ssBlock(SER_NETWORK, PROTOCOL_VERSION);
        ssBlock << pblockindex->GetBlockHeader();
        std::string strHex = HexStr(ssBlock.begin(), ssBlock.end());
        return strHex;
    }

    return blockheaderToJSON(pblockindex); // 4. 把区块头封装为 JSON 格式并返回
}
```

### 1. 帮助内容

参考[比特币 RPC 命令「getbestblockhash」1. 帮助内容](/blog/2018/05/bitcoin-rpc-getbestblockhash.html#1-帮助内容)。

### 2. 检查区块是否存在

参考[比特币 RPC 命令「getblock」2. 检查区块是否存在](/blog/2018/05/bitcoin-rpc-getblock.html#2-检查区块是否存在)。

### 3. 序列化区块头并返回

参考[比特币 RPC 命令「getblock」5. 序列化区块并返回](/blog/2018/05/bitcoin-rpc-getblock.html#5-序列化区块并返回)。

获取区块头函数 `pblockindex->GetBlockHeader()` 实现在文件 `chain.h` 中。

```cpp
/** The block chain is a tree shaped structure starting with the
 * genesis block at the root, with each block potentially having multiple
 * candidates to be the next block. A blockindex may have multiple pprev pointing
 * to it, but at most one of them can be part of the currently active branch.
 */
class CBlockIndex
{
public:
    //! pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
    const uint256* phashBlock; //! 指向区块哈希的指针(如果存在)。内存属于该 CBlockIndex

    //! pointer to the index of the predecessor of this block
    CBlockIndex* pprev; //! 指向该区块的上一块索引的指针
    ...
    //! block header
    int nVersion;
    uint256 hashMerkleRoot;
    unsigned int nTime;
    unsigned int nBits;
    unsigned int nNonce;
    ...
    CBlockHeader GetBlockHeader() const
    {
        CBlockHeader block;
        block.nVersion       = nVersion;
        if (pprev)
            block.hashPrevBlock = pprev->GetBlockHash();
        block.hashMerkleRoot = hashMerkleRoot;
        block.nTime          = nTime;
        block.nBits          = nBits;
        block.nNonce         = nNonce;
        return block;
    }

    uint256 GetBlockHash() const
    {
        return *phashBlock;
    }
    ...
};
```

### 4. 把区块头封装为 JSON 格式并返回

把区块头封装为 JSON 格式函数 `blockheaderToJSON(pblockindex)` 实现在文件 `rpcblockchain.cpp` 中。

```cpp
UniValue blockheaderToJSON(const CBlockIndex* blockindex)
{
    UniValue result(UniValue::VOBJ);
    result.push_back(Pair("hash", blockindex->GetBlockHash().GetHex())); // 区块哈希
    int confirmations = -1;
    // Only report confirmations if the block is on the main chain
    if (chainActive.Contains(blockindex)) // 仅当区块在主链上时报告确认数
        confirmations = chainActive.Height() - blockindex->nHeight + 1; // 计算确认数
    result.push_back(Pair("confirmations", confirmations)); // 确认数
    result.push_back(Pair("height", blockindex->nHeight)); // 区块高度
    result.push_back(Pair("version", blockindex->nVersion)); // 区块版本号
    result.push_back(Pair("merkleroot", blockindex->hashMerkleRoot.GetHex())); // 默克尔树根哈希
    result.push_back(Pair("time", (int64_t)blockindex->nTime)); // 区块创建时间
    result.push_back(Pair("mediantime", (int64_t)blockindex->GetMedianTimePast())); // 区块中间时间
    result.push_back(Pair("nonce", (uint64_t)blockindex->nNonce)); // 随机数
    result.push_back(Pair("bits", strprintf("%08x", blockindex->nBits))); // 难度对应值
    result.push_back(Pair("difficulty", GetDifficulty(blockindex))); // 难度
    result.push_back(Pair("chainwork", blockindex->nChainWork.GetHex())); // 链工作量

    if (blockindex->pprev) // 上一个区块的哈希
        result.push_back(Pair("previousblockhash", blockindex->pprev->GetBlockHash().GetHex()));
    CBlockIndex *pnext = chainActive.Next(blockindex);
    if (pnext) // 下一个区块的哈希
        result.push_back(Pair("nextblockhash", pnext->GetBlockHash().GetHex()));
    return result;
}
```

## 参考链接

* [bitcoin/rpcserver.h at v0.12.1 · bitcoin/bitcoin](https://github.com/bitcoin/bitcoin/blob/v0.12.1/src/rpcserver.h){:target="_blank"}
* [bitcoin/rpcserver.cpp at v0.12.1 · bitcoin/bitcoin](https://github.com/bitcoin/bitcoin/blob/v0.12.1/src/rpcserver.cpp){:target="_blank"}
* [bitcoin/chain.h at v0.12.1 · bitcoin/bitcoin](https://github.com/bitcoin/bitcoin/blob/v0.12.1/src/chain.h){:target="_blank"}
* [bitcoin/rpcblockchain.cpp at v0.12.1 · bitcoin/bitcoin](https://github.com/bitcoin/bitcoin/blob/v0.12.1/src/rpcblockchain.cpp){:target="_blank"}