比特币区块
比特币区块由区块头和该区块所包含的交易列表组成。区块头大小为80字节,其构成包括:
4字节:版本号
32字节:上一个区块的哈希值
32字节:交易列表的Merkle根哈希值
4字节:当前时间戳
4字节:当前难度值
4字节:随机数Nonce值
此80字节长度的区块头,即为比特币Pow算法的输入字符串。
交易列表附加在区块头之后,其中第一笔交易为矿工获得奖励和手续费的特殊交易。
//src/primitives/block.h
class CBlockHeader
{
public:
//版本号
int32_t
nVersion;
//上一个区块的哈希值
uint256
hashPrevBlock;
//交易列表的Merkle根哈希值
uint256
hashMerkleRoot;
//当前时间戳
uint32_t
nTime;
//当前挖矿难度,nBits越小难度越大
uint32_t
nBits;
//随机数Nonce值
uint32_t
nNonce;
//其它代码略
};
class CBlock : public CBlockHeader
{
public:
//交易列表
std::vector
vtx;
//其它代码略
};
算法原理
Pow的过程,即为不断调整Nonce值,对区块头做双重SHA256哈希运算,使得结果满足给定数量前导0的哈希值的过程。其中前导0的个数,取决于挖矿难度,前导0的个数越多,挖矿难度越大。简单来说,挖矿就是用不同的随机数重复计算区块头的哈希值,直到找到一个满足条件的哈希值。
具体如下:
1、生成铸币交易,并与其它所有准备打包进区块的交易组成交易列表,生成Merkle根哈希值。
2、将Merkle根哈希值,与区块头其它字段组成区块头,80字节长度的区块头作为Pow算法的输入。
3、不断变更区块头中的随机数Nonce,对变更后的区块头做双重SHA256哈希运算,与当前难度的目标值做比对,如果小于目标难度,即Pow完成。
Pow完成的区块向全网广播,其他节点将验证其是否符合规则,如果验证有效,其他节点将接收此区块,并附加在已有区块链之后。之后将进入下一轮挖矿。
SHA256(
SHA256(nVersion, hashPrevBlock, hashMerkleRoot, nTime, nBits,
nNonce)
) < TARGET
//Pow算法实现src/rpc/mining.cpp
UniValue generateBlocks(std::shared_ptr coinbaseScript, int
nGenerate, uint64_t nMaxTries, bool keepScript)
{
static const
int nInnerLoopCount = 0x10000;
int
nHeightEnd = 0;
int nHeight
= 0;
{ // Don't keep cs_main
locked
LOCK(cs_main);
nHeight = chainActive.Height();
nHeightEnd = nHeight+nGenerate;
}
unsigned int
nExtraNonce = 0;
UniValue
blockHashes(UniValue::VARR);
while
(nHeight < nHeightEnd)
{
std::unique_ptr
pblocktemplate(BlockAssembler(Params()).CreateNewBlock(coinbaseScript->reserveScript));
if (!pblocktemplate.get())
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new
block");
CBlock *pblock = &pblocktemplate->block;
{
LOCK(cs_main);
IncrementExtraNonce(pblock, chainActive.Tip(), nExtraNonce);
}
//不断变更区块头中的随机数Nonce
//对变更后的区块头做双重SHA256哈希运算
//与当前难度的目标值做比对,如果小于目标难度,即Pow完成
//uint64_t nMaxTries = 1000000;即重试100万次
while (nMaxTries > 0 && pblock->nNonce <
nInnerLoopCount && !CheckProofOfWork(pblock->GetHash(),
pblock->nBits, Params().GetConsensus())) {
++pblock->nNonce;
--nMaxTries;
}
if (nMaxTries == 0) {
break;
}
if (pblock->nNonce == nInnerLoopCount) {
continue;
}
std::shared_ptr shared_pblock = std::make_shared(*pblock);
if (!ProcessNewBlock(Params(), shared_pblock, true, nullptr))