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