比特币挖矿之区块校验

http://e.c60block.com/2018/03/09/%E6%AF%94%E7%89%B9%E5%B8%81%E6%8C%96%E7%9F%BF%E4%B9%8B%E5%8C%BA%E5%9D%97%E6%A0%A1%E9%AA%8C/

 © 碳60 区块链

比特币挖矿之矿工任务中我们提到,矿工的首要任务是同步区块链已有数据,监听新区块。当新的区块在网络中传播时,每一个全节点在将它转发到其他节点之前,会进行一系列的测试去验证区块的合法性。下面我们将对校验标准进行具体介绍。

区块校验

比特币区块的校验标准如下:
1、区块头的的哈希值满足当前目标值(工作量证明)
2、重构Merkle树得到的树根与区块头中hashMerkleRoot值一致(验证MerkleRoot是否由区块中交易得到)
3、区块大小在长度限制内
4、第一个交易是coinbase交易,且其他交易都不是coinbase交易
5、遍历区块内所有交易,检查交易合法性

以上的校验标准主要在比特币核心客户端的CheckBlock函数中获得,具体源码如下:

bool CheckBlock(const CBlock& block, CValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
{
    // These are checks that are independent of context.
    
    // 如果区块已经检查过,则直接返回结果true
    if (block.fChecked)
        return true;
    
    // 检查区块头是否满足工作量要求 
    if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
        return false;

    // 判断是否校验MerkleRoot 若检查,则校验MerkleRoot是否符合要求,是否存在重复交易
    if (fCheckMerkleRoot) {
        bool mutated;
        // 重新构建一遍Merkle树,返回MerkleRoot
        uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated);
        if (block.hashMerkleRoot != hashMerkleRoot2)
            return state.DoS(100, false, REJECT_INVALID, "bad-txnmrklroot",true, "hashMerkleRoot mismatch");

        // Check for merkle tree malleability (CVE-2012-2459): repeating sequences
        // of transactions in a block without affecting the merkle root of a block,
        // while still invalidating it.
        if (mutated)
            return state.DoS(100, false, REJECT_INVALID, "bad-txns-duplicate",true, "duplicate transaction");
    }

    // 在我们做任何的交易校验之前,应该首先做潜在的问题校验,这样一旦我们发现问题,便可以将区块头标记为无效 隔离见证数据并不在此处校验

    // 大小限制
    // 区块交易不为空,至少存在coinbase交易
    // 区块size和weight符合要求
    if (block.vtx.empty() || block.vtx.size() * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT || ::GetSerializeSize(block, SER_NETWORK, PROTOCOL_VERSION| SERIALIZE_TRANSACTION_NO_WITNESS) * WITNESS_SCALE_FACTOR > MAX_BLOCK_WEIGHT)
            return state.DoS(100, false, REJECT_INVALID, "bad-blk-length",false, "size limits failed");
    
    // First transaction must be coinbase, the rest must not be
    // 校验首个交易是否是coinbase交易
    if (block.vtx.empty() || !block.vtx[0]->IsCoinBase())
        return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false,"first tx is not coinbase");
    // 校验coinbase交易是否唯一
    for (unsigned int i = 1; i < block.vtx.size(); i++)
        if (block.vtx[i]->IsCoinBase())
            return state.DoS(100, false, REJECT_INVALID, "bad-cb-multiple",false, "more than one coinbase");

    // Check transactions
    // 校验交易是否符合要求,此函数将在比特币挖矿之交易校验中具体介绍
    for (const auto& tx : block.vtx)
        if (!CheckTransaction(*tx, state, false))
            return state.Invalid(false, state.GetRejectCode(),state.GetRejectReason(),strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), state.GetDebugMessage()));

    unsigned int nSigOps = 0;
    for (const auto& tx : block.vtx)
    {
        nSigOps += GetLegacySigOpCount(*tx);
    }
    if (nSigOps * WITNESS_SCALE_FACTOR > MAX_BLOCK_SIGOPS_COST)
        return state.DoS(100, false, REJECT_INVALID, "bad-blk-sigops", false,"out-of-bounds SigOpCount");

    if (fCheckPOW && fCheckMerkleRoot)
        block.fChecked = true;

    return ture;
}

检查区块头是否满足工作量要求

static bool CheckBlockHeader(const CBlockHeader& block, CValidationState&state, const Consensus::Params& consensusParams, bool fCheckPOW = true)
{
    // Check proof of work matches claimed amount
    // 检查工作量难度是否满足声明要求
    // CheckProofOfWork方法已经在比特币挖矿之随机数中介绍过
    if (fCheckPOW && !CheckProofOfWork(block.GetHash(), block.nBits,consensusParams))
        return state.DoS(50, false, REJECT_INVALID, "high-hash", false, "proof of work failed");
    
    return ture;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章