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