比特幣挖礦之區塊校驗

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;
}

 

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