上一篇基本認識了bitcoin源碼結構和個模塊代碼的功能,今天看區塊。html
區塊是組成區塊的基本單位,咱們能夠經過bitcoin-cli命令查看一個區塊的基本信息。node
接下來咱們就在源代碼找一下區塊的定義,因爲咱們並不知道區塊定義在哪。咱們試着全局搜一下block.h(或block.cpp):算法
進去發現還真被我找到了,其實咱們在上一篇的bitcoin源碼結構的目錄結構裏已經說過./private目錄下是區塊類和交易類的實現。接下來,就讓咱們一窺block的究竟。網絡
/** 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. * **網絡中的節點不斷收集新的交易打包到區塊中,全部的交易會經過兩兩哈希的方式造成一個Merkle樹 * 打包的過程就是要完成工做量證實的要求,當節點解出了當前的隨機數時, * 它就把當前的區塊廣播到其餘全部節點,而且加到區塊鏈上。 * 區塊中的第一筆交易稱之爲CoinBase交易,是產生的新幣,獎勵給區塊的產生者 * * add by chaors 20180419 */
class CBlockHeader {
public:
// header
int32_t nVersion; //版本
uint256 hashPrevBlock; //上一個區塊的hash
uint256 hashMerkleRoot; //包含交易信息的Merkle樹根
uint32_t nTime; //時間戳
uint32_t nBits; //工做量證實(POW)的難度
uint32_t nNonce; //要找的符合POW的隨機數
CBlockHeader() //構造函數初始化成員變量
{
SetNull();
}
ADD_SERIALIZE_METHODS; //經過封裝的模板實現類的序列化
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說明區塊還未建立,區塊頭爲空
}
uint256 GetHash() const; //獲取哈希
int64_t GetBlockTime() const //獲取區塊時間
{
return (int64_t)nTime;
}
};
複製代碼
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;
};
複製代碼
/** 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.
*
**描述區塊鏈中在其餘節點的一個位置,
*若是其餘節點沒有相同的分支,它能夠找到一個最近的中繼(最近的相同塊)。
*更進一步地講,它多是分叉前的一個位置
*/
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();
}
};
複製代碼
uint256 CBlockHeader::GetHash() const
{
return SerializeHash(*this); //生成256位的哈希值
}
std::string CBlock::ToString() const //區塊對象格式化字符串輸出
{
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();
}
複製代碼
區塊是經過先後連接構成區塊鏈的一種容器數據結構。它由描述區塊主要信息的區塊頭和包含若干交易數據的區塊共同組成。區塊頭是80字節,而平均每一個交易至少是250字節,並且平均每一個區塊至少包含超過500個交易。因此,一個區塊是比區塊頭大好多的數據體。這也是比特幣驗證交易是否存在採用Merkcle樹的緣由。數據結構
數據項 | 大小(Byte) | 描述 |
---|---|---|
Block Size | 4 | 區塊大小 |
Block Header | 80 | 區塊頭信息大小 |
Transactions | m*n(n>=250) | 全部交易的列表 |
Transactions Counter | 1-9 | 交易數額 |
比特幣的區塊大小目前被嚴格限制在1MB之內。4字節的區塊大小字段不包含在此內!函數
數據項 | 大小(Byte) | 存儲方式 | 描述 |
---|---|---|---|
Version | 4 | 小端 | 區塊版本,規定了區塊遵照的驗證規則 |
Previous Block Hash | 32 | 內部字節順序 | 上一個區塊哈希值(SHA256 (SHA256(Block Header))) |
Merkle Root | 32 | 內部字節順序 | Merkle樹根,包含了全部交易的哈希 |
Timestamp | 4 | 小端 | 區塊產生時間戳,大於前11個區塊時間戳的平均值,全節點會拒絕時間戳超出本身2小時的區塊 |
nBitS | 4 | 小端 | 工做量證實(POW)的目標難度值,當前區塊難度值須要通過Target nBits編碼才能轉化爲目標哈希值 |
Nonce | 4 | 小端 | 用於POW的一個隨機數,隨着算力增大可能會致使Nonce位數不夠 協議規定時間戳和CoinbaseTransaction信息可修改用於擴展Nonce位數 |
BlockHash 區塊哈希值,是經過SHA256算法對區塊頭信息進行哈希獲得的,這個值必須知足POW的DifficultyTarget,該區塊才被認爲有效。同時,也是區塊的惟一標識符,能夠經過經過bitcoin-cli根據BlockHash查詢區塊信息(文章開頭咱們就使用過)post
BlockHeight 區塊高度,是用來標示區塊在區塊鏈中的位置。創世區塊高度爲0,每個加在後面的區塊,區塊高度遞增1。能夠經過bitcoin-cli根據高度查詢區塊哈希值(文章開頭咱們就使用過)區塊鏈
區塊鏈上第一個區塊被稱爲創世區塊,它是全部區塊的共同祖先。咱們能夠查看下比特幣的創世區塊:ui
比特幣創始人聰哥在創世區塊包含了一個隱藏的信息。在其Coinbase交易的輸入中包含這樣一句話「The Times 03/Jan/2009 Chancellor on brink of second bailout forbanks.」這句話是泰晤士報當天的頭版文章標題,聰哥這樣作的目的不得而知。可是,這樣一條非交易信息能夠垂手可得地插入比特幣,這個現象值得深思。如此,就不難理解前不久曝光的"不法分子利用比特幣存儲兒童色情內容"新聞,固然這種存儲可能遠比聰哥的那句話要更復雜一點。this
2.爲何區塊的哈希沒有定義在區塊頭內部?
對區塊的認識就告一段落,下一篇準備去探索比特幣數據結構-交易的結構。
. . . .
###互聯網顛覆世界,區塊鏈顛覆互聯網!
--------------------------------------------------20180419 23:20