上一篇基本認識了bitcoin源碼結(jié)構(gòu)和個模塊代碼的功能满俗,今天看區(qū)塊。
區(qū)塊是組成區(qū)塊的基本單位,我們可以通過bitcoin-cli命令查看一個區(qū)塊的基本信息降盹。
接下來我們就在源代碼找一下區(qū)塊的定義谤辜,由于我們并不知道區(qū)塊定義在哪丑念。我們試著全局搜一下block.h(或block.cpp):
進去發(fā)現(xiàn)還真被我找到了,其實我們在上一篇的bitcoin源碼結(jié)構(gòu)的目錄結(jié)構(gòu)里已經(jīng)說過./private目錄下是區(qū)塊類和交易類的實現(xiàn)渔彰。接下來推正,就讓我們一窺block的究竟植榕。
源碼初窺
CBlockHeader
/** Nodes collect new transactions into a block, hash them into a hash tree,
* and scan through nonce values to make the block's hash satisfy proof-of-work
* requirements. When they solve the proof-of-work, they broadcast the block
* to everyone and the block is added to the block chain. The first transaction
* in the block is a special one that creates a new coin owned by the creator
* of the block.
*
**網(wǎng)絡(luò)中的節(jié)點不斷收集新的交易打包到區(qū)塊中,所有的交易會通過兩兩哈希的方式形成一個Merkle樹
* 打包的過程就是要完成工作量證明的要求炒瘸,當節(jié)點解出了當前的隨機數(shù)時寝衫,
* 它就把當前的區(qū)塊廣播到其他所有節(jié)點慰毅,并且加到區(qū)塊鏈上。
* 區(qū)塊中的第一筆交易稱之為CoinBase交易技俐,是產(chǎn)生的新幣统台,獎勵給區(qū)塊的產(chǎn)生者
*
* add by chaors 20180419
*/
class CBlockHeader
{
public:
// header
int32_t nVersion; //版本
uint256 hashPrevBlock; //上一個區(qū)塊的hash
uint256 hashMerkleRoot; //包含交易信息的Merkle樹根
uint32_t nTime; //時間戳
uint32_t nBits; //工作量證明(POW)的難度
uint32_t nNonce; //要找的符合POW的隨機數(shù)
CBlockHeader() //構(gòu)造函數(shù)初始化成員變量
{
SetNull();
}
ADD_SERIALIZE_METHODS; //通過封裝的模板實現(xiàn)類的序列化
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(this->nVersion);
READWRITE(hashPrevBlock);
READWRITE(hashMerkleRoot);
READWRITE(nTime);
READWRITE(nBits);
READWRITE(nNonce);
}
void SetNull() //初始化成員變量
{
nVersion = 0;
hashPrevBlock.SetNull();
hashMerkleRoot.SetNull();
nTime = 0;
nBits = 0;
nNonce = 0;
}
bool IsNull() const
{
return (nBits == 0); //難度為0說明區(qū)塊還未創(chuàng)建贱勃,區(qū)塊頭為空
}
uint256 GetHash() const; //獲取哈希
int64_t GetBlockTime() const //獲取區(qū)塊時間
{
return (int64_t)nTime;
}
};
CBlock
class CBlock : public CBlockHeader //繼承自CBlockHeader谤逼,擁有其所有成員變量
{
public:
// network and disk
std::vector<CTransactionRef> vtx; //所有交易的容器
// memory only
mutable bool fChecked; //交易是否驗證
CBlock()
{
SetNull();
}
CBlock(const CBlockHeader &header)
{
SetNull();
*((CBlockHeader*)this) = header;
}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(*(CBlockHeader*)this);
READWRITE(vtx);
}
void SetNull()
{
CBlockHeader::SetNull();
vtx.clear();
fChecked = false;
}
CBlockHeader GetBlockHeader() const
{
CBlockHeader block;
block.nVersion = nVersion;
block.hashPrevBlock = hashPrevBlock;
block.hashMerkleRoot = hashMerkleRoot;
block.nTime = nTime;
block.nBits = nBits;
block.nNonce = nNonce;
return block;
}
std::string ToString() const;
};
CBlockLocator
/** Describes a place in the block chain to another node such that if the
* other node doesn't have the same branch, it can find a recent common trunk.
* The further back it is, the further before the fork it may be.
*
**描述區(qū)塊鏈中在其他節(jié)點的一個位置,
*如果其他節(jié)點沒有相同的分支纹坐,它可以找到一個最近的中繼(最近的相同塊)耘子。
*更進一步地講,它可能是分叉前的一個位置
*/
struct CBlockLocator
{
std::vector<uint256> vHave;
CBlockLocator() {}
explicit CBlockLocator(const std::vector<uint256>& vHaveIn) : vHave(vHaveIn) {}
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
int nVersion = s.GetVersion();
if (!(s.GetType() & SER_GETHASH))
READWRITE(nVersion);
READWRITE(vHave);
}
void SetNull()
{
vHave.clear();
}
bool IsNull() const
{
return vHave.empty();
}
};
. cpp函數(shù)
uint256 CBlockHeader::GetHash() const
{
return SerializeHash(*this); //生成256位的哈希值
}
std::string CBlock::ToString() const //區(qū)塊對象格式化字符串輸出
{
std::stringstream s;
s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
GetHash().ToString(),
nVersion,
hashPrevBlock.ToString(),
hashMerkleRoot.ToString(),
nTime, nBits, nNonce,
vtx.size());
for (const auto& tx : vtx) {
s << " " << tx->ToString() << "\n";
}
return s.str();
}
區(qū)塊結(jié)構(gòu)分析
區(qū)塊是通過前后鏈接構(gòu)成區(qū)塊鏈的一種容器數(shù)據(jù)結(jié)構(gòu)绒障。它由描述區(qū)塊主要信息的區(qū)塊頭和包含若干交易數(shù)據(jù)的區(qū)塊共同組成户辱。區(qū)塊頭是80字節(jié)糙臼,而平均每個交易至少是250字節(jié),而且平均每個區(qū)塊至少包含超過500個交易焚鹊。所以韧献,一個區(qū)塊是比區(qū)塊頭大好多的數(shù)據(jù)體。這也是比特幣驗證交易是否存在采用Merkcle樹的原因璧针。
整體結(jié)構(gòu)
數(shù)據(jù)項 | 大小(Byte) | 描述 |
---|---|---|
Block Size | 4 | 區(qū)塊大小 |
Block Header | 80 | 區(qū)塊頭信息大小 |
Transactions | m*n(n>=250) | 所有交易的列表 |
Transactions Counter | 1-9 | 交易數(shù)額 |
比特幣的區(qū)塊大小目前被嚴格限制在1MB以內(nèi)探橱。4字節(jié)的區(qū)塊大小字段不包含在此內(nèi)!
區(qū)塊頭
數(shù)據(jù)項 | 大小(Byte) | 存儲方式 | 描述 |
---|---|---|---|
Version | 4 | 小端 | 區(qū)塊版本绘证,規(guī)定了區(qū)塊遵守的驗證規(guī)則 |
Previous Block Hash | 32 | 內(nèi)部字節(jié)順序 | 上一個區(qū)塊哈希值(SHA256 (SHA256(Block Header))) |
Merkle Root | 32 | 內(nèi)部字節(jié)順序 | Merkle樹根嚷那,包含了所有交易的哈希 |
Timestamp | 4 | 小端 | 區(qū)塊產(chǎn)生時間戳,大于前11個區(qū)塊時間戳的平均值腐泻,全節(jié)點會拒絕時間戳超出自己2小時的區(qū)塊 |
nBitS | 4 | 小端 | 工作量證明(POW)的目標難度值,當前區(qū)塊難度值需要經(jīng)過Target nBits編碼才能轉(zhuǎn)化為目標哈希值 |
Nonce | 4 | 小端 | 用于POW的一個隨機數(shù)构诚,隨著算力增大可能會導致Nonce位數(shù)不夠 協(xié)議規(guī)定時間戳和CoinbaseTransaction信息可修改用于擴展Nonce位數(shù) |
區(qū)塊標識符
BlockHash 區(qū)塊哈希值铆惑,是通過SHA256算法對區(qū)塊頭信息進行哈希得到的,這個值必須滿足POW的DifficultyTarget鸭津,該區(qū)塊才被認為有效逆趋。同時晒奕,也是區(qū)塊的唯一標識符,可以通過通過bitcoin-cli根據(jù)BlockHash查詢區(qū)塊信息(文章開頭我們就使用過)
BlockHeight 區(qū)塊高度魄眉,是用來標示區(qū)塊在區(qū)塊鏈中的位置闷袒。創(chuàng)世區(qū)塊高度為0,每一個加在后面的區(qū)塊晃择,區(qū)塊高度遞增1也物』牵可以通過bitcoin-cli根據(jù)高度查詢區(qū)塊哈希值(文章開頭我們就使用過)
注:BlockHeight并不是唯一標識符,當區(qū)塊鏈出現(xiàn)臨時分叉時坤次,會有兩個區(qū)塊的高度值相同的情況斥赋。
創(chuàng)世區(qū)塊
區(qū)塊鏈上第一個區(qū)塊被稱為創(chuàng)世區(qū)塊,它是所有區(qū)塊的共同祖先洛波。我們可以查看下比特幣的創(chuàng)世區(qū)塊:
比特幣創(chuàng)始人聰哥在創(chuàng)世區(qū)塊包含了一個隱藏的信息蹬挤。在其Coinbase交易的輸入中包含這樣一句話“The Times 03/Jan/2009 Chancellor on brink of second bailout forbanks.”這句話是泰晤士報當天的頭版文章標題,聰哥這樣做的目的不得而知倦零。但是吨悍,這樣一條非交易信息可以輕而易舉地插入比特幣,這個現(xiàn)象值得深思葫隙。如此躏仇,就不難理解前不久曝光的"不法分子利用比特幣存儲兒童色情內(nèi)容"新聞,當然這種存儲可能遠比聰哥的那句話要更復雜一點糟描。
思考
- 我們查看的區(qū)塊信息中书妻,以下不在源碼結(jié)構(gòu)中的字段有什么含義躲履?為什么他們不在源碼定義的區(qū)塊結(jié)構(gòu)中?
confirmations
strippedsize
weight
mediantime
bits
chainwork
- 我們查看的區(qū)塊信息中书妻,以下不在源碼結(jié)構(gòu)中的字段有什么含義躲履?為什么他們不在源碼定義的區(qū)塊結(jié)構(gòu)中?
2.為什么區(qū)塊的哈希沒有定義在區(qū)塊頭內(nèi)部缤剧?
注:以上問題可能我也沒答案域慷,可以留言我們一起交流共同進步。
對區(qū)塊的認識就告一段落抵窒,下一篇準備去探索比特幣數(shù)據(jù)結(jié)構(gòu)-交易的結(jié)構(gòu)叠骑。
參考文獻
.
.
.
.
互聯(lián)網(wǎng)顛覆世界,區(qū)塊鏈顛覆互聯(lián)網(wǎng)!
--------------------------------------------------20180419 23:20