前言
我們知道區塊鏈是由多個區塊連結而成的一條鏈,每一個區塊都包含著一些資料,我們通過比特幣區塊的解析來了解一下區塊鏈。
區塊結構
比特幣大概每10分鐘左右產生一個區塊,每個區塊的容量是中本聰設定的1M大小。我們可以在blockchain這個網站上看到最近產生的區塊。
一個完整的區塊包括以下5塊內容:
名稱 | 資料大小 | 說明 |
---|---|---|
魔數(Magic NO) | 4位元組 | 總為常數0xD9B4BEF9,作為區塊之間的分隔符 |
區塊大小(Blocksize) | 4位元組 | 用於記錄當前區塊的大小(即該欄位之後的區塊大小) |
區塊頭(Blockheader) | 80位元組 | 記錄當前區塊頭上的一些資訊 |
交易計數(Transaction counter) | 1-9位元組 | 該區塊包含的交易數量,包含coinbase交易 |
交易詳情(Transactions) | 不定 | 包含了當前區塊儲存的所有交易細節 |
區塊內容解析
我們從webbtc裡隨便選一個區塊,看到內容如下圖所示:
這裡是從區塊裡讀出的一個資料的概要。具體的原始資料可以檢視Formats那一行,一個是json資料,一個是十六進位制的資料,還有一個是二進位制的資料。我們這裡直接檢視json資料即可。下面我把整個json資料分成了三個部分便於檢視。
當前區塊Hasn、區塊頭、交易計數、區塊大小
{
"hash": "000000000000000001806a922d4d35a37ad9324c690f72d556c6445cb7a9c214",
"ver": 536870914,
"prev_block": "000000000000000000f061205567dc79c4e718209a568879d66132e016968ac6",
"mrkl_root": "83f5fdf40b0b02c09ae669041df1bedfc635c45f696057a8c29e1bde1f4cbd24",
"time": 1482006384,
"bits": 402885509,
"nonce": 636041063,
"n_tx": 20,
"size": 6264
}
複製程式碼
當前區塊Hasn
我們看這段json資料,第一個是當前區塊的Hash,但它並不儲存在區塊的資料結構裡,不管是該區塊在網路上傳輸時,抑或是它作為區塊鏈的一部分被儲存在某節點的永久性儲存裝置上時。相反,區塊雜湊值是當該區塊從網路被接收時由每個節點計算出來的。區塊的雜湊值可能會作為區塊後設資料的一部分被儲存在一個獨立的資料庫表中,以便於索引和更快地從磁碟檢索區塊。
簡單的說就是這個值被算出來後在本地資料庫或快取中,然後供下個區塊生成或者是到來較驗用,然後在下一個區塊生成時,在下一個區塊的區塊頭中儲存。
區塊頭
//bitcoin 區塊頭的程式碼
class CBlockHeader
{
public:
// header
int32_t nVersion;
uint256 hashPrevBlock;
uint256 hashMerkleRoot;
uint32_t nTime;
uint32_t nBits;
uint32_t nNonce;
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);
}
uint256 GetHash() const;
int64_t GetBlockTime() const
{
return (int64_t)nTime;
}
};
複製程式碼
區塊頭包含以下6個部分:版本、父區塊頭雜湊值、Merkle根、時間戳、難度目標、隨機數,總共80個位元組。
名稱 | 資料大小 | 說明 |
---|---|---|
版本(ver) | 4位元組 | 資料區塊的版本號 |
父區塊頭雜湊值(prev_block) | 32位元組 | 記錄了前一個區塊的雜湊值,當前區塊的雜湊值一定比它小 |
Merkle根(mrkl_root) | 32位元組 | 該區塊中交易的Merkle樹根的雜湊,是根據當前區塊所有交易的雜湊值生成的 |
時間戳(time) | 4位元組 | 該區塊產生的近似時間,精確到秒的UNIX時間戳,必須嚴格大於前11個區塊時間的中值,同時全節點也會拒絕那些超出自己2個小時時間戳的區塊 |
難度目標(bits) | 4位元組 | 該區塊工作量證明演算法的難度目標,已經使用特定演算法編碼 |
隨機數(nonce) | 4位元組 | 為了找到滿足難度目標所設定的隨機數,為了解決32位隨機數在算力飛昇的情況下不夠用的問題,規定時間戳和coinbase交易資訊均可更改,以此擴充套件nonce的位數 |
交易計數
n_tx即是當前區塊的交易計數,我們能看到一共有20筆
區塊大小
size即為當前區塊的大小,這裡看到的為6264位元組
交易詳情
以下資料即為交易詳情,一共20筆,我這裡只取了其中的兩筆交易,其中第一筆為coinbase交易,即由挖礦產生的比特幣獎勵。
{ "tx": [
{
"hash": "f94528b2012446f4e367694871d07d5c726788e2f20d5553161a24debbec5118",
"ver": 1,
"vin_sz": 1,
"vout_sz": 1,
"lock_time": 0,
"size": 154,
"in": [
{
"prev_out": {
"hash": "0000000000000000000000000000000000000000000000000000000000000000",
"n": 4294967295
},
"coinbase": "03efc506fabe6d6d3146d1ecf0c8b111d52ee100ef81dc1ab32ce28f4f6b677e9eb0f0a5032fa9270100000000000000016506008508ed705d0000ea6e1c2f736c7573682f",
"sequence": 0
}
],
"out": [
{
"value": "12.50503278",
"scriptPubKey": "OP_DUP OP_HASH160 7c154ed1dc59609e3d26abb2df2ea3d587cd8c41 OP_EQUALVERIFY OP_CHECKSIG",
"address": "1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE"
}
],
"nid": "0f66ac12827c122c2df335ba8c4d89ca0d0b071cab39ab1e6b436ed3fb246d36"
},
{
"hash": "c8a340969b594332876f357207083a6a36b3269e37302315e8bef05032105346",
"ver": 1,
"vin_sz": 1,
"vout_sz": 2,
"lock_time": 0,
"size": 334,
"in": [
{
"prev_out": {
"hash": "8529367f8e6d3cf34fe702eb05a18e67e521385835e735e5c69184b14d19f688",
"n": 1
},
"scriptSig": "0 30450221009c1503bc1500b58aab48bfe62d40fb511a03193e8a7fbdefde4915949dc2ade902207920d7a86e819b568d34d931871d94824cec8dad63dc977d354b65264380907501 304502210095b2184dd3649e2a5025cd8e67a2c3aad6dc022848160f169006c322d77f67d302205ff0f8417126650c5b5e71abc64e37c1769a312d613602b96a944a8281f6c69c01 5221032284521d6790130f7043136a14b60119cea371c754cb3743b56c61b7d495d6e42103f15e3cdd49c26ea7b00c9b5ddeac06129033ac38e5a0b739883e0b302138ec3552ae"
}
],
"out": [
{
"value": "0.00149700",
"scriptPubKey": "OP_HASH160 88196be31c9252c3895e495bd657d7dd389ddd94 OP_EQUAL"
},
{
"value": "0.00824600",
"scriptPubKey": "OP_HASH160 d4dc84eedfec38bad0510d364b2c8fd4fce57151 OP_EQUAL"
}
],
"nid": "ccd4371ec31f533884416959ad1e5503c9be5fb3262d7a40fc6ec58f9cf54090"
}
·
·
·
·
]
}
複製程式碼
我們能看到每一筆都有輸入和輸出,以及交易雜湊、版本號等等。
默克樹(Merkle Tree)
{
"mrkl_tree": [
"f94528b2012446f4e367694871d07d5c726788e2f20d5553161a24debbec5118",
"c8a340969b594332876f357207083a6a36b3269e37302315e8bef05032105346",
"460bf9d5db9f1df960c03b5225316ac77d1965b8f4ac429e0e66a6e097018a07",
"104bf4664aab45e8e20274fbed530eccf22af9565e10597bd63965f0bbbf11ff",
"9b49a5734b040cfcd370c0af924f590d79eceb1cfb77b655770713bff9e01281",
"8da9855406072b487dc14c05f9d1fb98eaea5cdf802aafe9a361fd23531db819",
"9430c839d5605f59ed7a47ed59d50c1cec2d62e771f7a02bfbb17d91416af4b9",
"ebe8e007b49aceef46e3971564802b049029a9bdc31d2ed1b0be23633b01236b",
"26ffe42a53c5caabd37ca0a260d3e6e15d0dbdb30cd641d8fa2690f065b5b712",
"358f05fb03bad69fb4ebcef9a74dea2a7fd4368e31e0ac7794a155f4930ba4e6",
"8d1ab4e9c5b788d97f126a7c22ab67b8326cbed2d1b992bbc8dcdbb74b13bf7d",
"4c2980e9bca8044f61db1e1422fb92aab50389517c8d8da8dca79ae2d73776c4",
"72fa5baf9250e5226afaaa1dd7194912027407111642f1e420e42f52023eba60",
"3facb7091d0c4330735b3d184662a52902c820e98de65ac692075abb2d917db7",
"46c33ae0d9f03cc97bcb94013f4c54640614db1768728c928d0ac7ebd9f8c1c9",
"6dcaec17dc034f242166c8e2161acbefcf3b30087a96ed621da7cdccc8ff3002",
"40edfee9764baab18bbe375fa5d15c26ecdf109f90fa27522809902c441e45ab",
"45b3093eb524baa5b078f73755b80789af733c78c16ec612ed435860c33020fa",
"2b05f2168afc22d73b929fbdcb8e38fea969fa1fbe7cb6e10efb37e876f5cfe2",
"323c7c81cff26c38171c4740d5163ff5ef0ab23de80a2a069f95405d0945b693",
"99deb2a2f7d199062e3a075e9bb0b58f7fb8498621e799e3365e1a3c4c255d8d",
"ecfc6aea54b4d7e517a3170d291bde5f9edb0119dedf8193b8ddf90e583c19cc",
"c549c24b1575ada64dd21a5b59f6018e44d9e4caec0a0505f034b7d4cb54c7d9",
"c9001c84acba3b2e5c2020344552d29a09460dd86906757394caa80c49b84c08",
"197eb574bcbf4b85c934bc985a15bfc6f2e5da513e5e8ccc9206a50edd66297f",
"4e92a4eb49c494146a5172b0dddb903013d478c82f7c9da81a675872468ac7d6",
"7849c98a4bd4af150eb9c954cda0734a9dbcf9e2f88e34480bc910544d3fdf4c",
"dfd05872158c2a78923159f1cb1182c89641398967c458d768bdb422c397fa57",
"9b27fb4636d299311abb6015ca27760e408fce7802d196fa14a0a9470e219bbb",
"da9b1c4deda656cc215646f204700b7829fd72a2e2ebd967e1fa01e1811c7ec1",
"b81ab1b0c6cc42fdb56176ede115bee5b66a571ebbf8053f6510fdd3a9927501",
"7ca0e3b3e7cc193fbc1f6553cfca35b3358727b3107c0d5914311685bdf761a8",
"5ce961502e61d22b77860d478dfb0b4073ba5249b11aaba32e2c13db4b4356c7",
"c1a84c7a58fdf92834b05aadffaaaeef4745ea60a8914a250b010e581839221a",
"f1e7cbe4a5f916c87fab0049eaccd6dc825ca7ac495575c01a3fc9b358d2c377",
"bebd7be3317d84cce8c2674d39c883a4218d218294f7154c33359c34b7437fbb",
"91f5ea3df74833e2dd94ecc2b8360a8a764a01c5c006baab88556b923434706a",
"2298fca6dc939e048c79721afeaadfa6f8056eb8006b1f1e2d1d653e6baa438f",
"bf57c77219a6d905440368629f593c4fb4c23cc35d68b7305cc8506bbdb4e452",
"513be8c874a6bba6259e0a44a709e5a58c1cb0f610612c35b9725227b7c2bd78",
"83f5fdf40b0b02c09ae669041df1bedfc635c45f696057a8c29e1bde1f4cbd24"
]
}
複製程式碼
上面為默克樹(Merkle Tree)的整個樹節點的資訊。儲存在區塊頭中的mrkl_root
就是由這個默克樹生成的,我們能看到以上陣列的最後一個Hash值跟區塊頭中的mrkl_root
相同,這個資料就是默克樹最後生成的默克根。所以我們一共20筆交易,那麼加上mrkl_root
一共就是20+10+5+3+2+1=41
個Hash值。下圖是一個簡單的默克樹生成過程:
比特幣使用默克樹的方式對交易進行驗證,相對於雜湊列表,默克樹是一種雜湊二叉樹,它的明顯的一個好處是可以單獨拿出一個分支來對部分資料進行校驗,更加高效。