cpp 區塊鏈模擬示例(二)工程代碼解析
書接上文
我們先來看區塊的結構
1 class Block { 2 public: 3 string sPrevHash; //記錄上個塊的哈希值 4 Block(uint32_t nIndexIn, const string &sDataIn); //構造函數 5 string GetHash(); //獲取哈希函數 6 void MineBlock(uint32_t nDifficulty); //挖礦函數 7 private: 8 uint32_t _nIndex; //該區塊的索引值 9 int64_t _nNonce; //區塊隨機數 用於哈希值的產生 10 string _sData; //區塊描述字符 11 string _sHash; //區塊哈希值 12 time_t _tTime; //創建時間 13 string _CalculateHash() const; //哈希值計算函數 14 };
區塊結構很清晰。 一個區塊就是一個創建時間、描述字符、區塊隨機數字等數據組成。
我們要創建一個區塊就是根據創建時間、描述字符、區塊隨機數字等數據來計算出一個哈希值(_CalculateHash函數的功能)。
inline string Block::_CalculateHash() const { stringstream ss; ss << _nIndex << _tTime << _sData << _nNonce << sPrevHash; return sha256(ss.str()); }
由於_nNonce與創建時間是一值在變化的,_CalculateHash()會產生一個個的哈希。
在MineBlock()函數中對這些哈希進行檢測,看看是否符合標準,一旦符合標準,那麽久誕生了一個區塊。
這裏的MineBlock()函數中,根據設置的DifficultyNum,來檢測哈希數值前DifficultyNum位是否為零,只有符合標準才是產生的區塊的可使用的哈希值
隨即產生的哈希值中,前DifficultyNum位為零,只在一定概率下才產生。 這也是為了限制區塊的產生速度,在本次區塊鏈技術模擬中,我們稱之為"工作量證明"
void Block::MineBlock(uint32_t nDifficulty) { char cstr[DifficultyNum + 1]; for (uint32_t i = 0; i < DifficultyNum; ++i) { cstr[i] = ‘0‘; } cstr[DifficultyNum] = ‘\0‘; string str(cstr); do { _nNonce++; _sHash = _CalculateHash(); } while (_sHash.substr(0, nDifficulty) != str); cout << "Block mined: " << _sHash << endl; }
Block 結構體中 sPrevHash就是記錄該區塊的上一個區塊的哈希值。區塊鏈技術中使用一種方法將哈希值與區塊一一對應。
這樣知道一個區塊和區塊中的sPrevHash。通過查找可以依次遍歷區塊鏈中的每個區塊。這些有關聯的區塊也正是使用這種方法組成了區塊鏈.
區塊鏈結構體如下
class Blockchain { public: Blockchain(); //區塊鏈構造函數 void AddBlock(Block bNew); //區塊鏈添加區塊函數 private: uint32_t _nDifficulty; //難度值 vector<Block> _vChain; //記錄區塊鏈 Block _GetLastBlock() const; //獲取最後一個區塊 };
大致的示意圖如下
我們的模擬文章中,區塊鏈使用了vector<Block> _vChain來記錄每個區塊,每個區塊中都有自己在這個vector中的索引_nIndex,這樣查找起來更簡單快捷。
區塊鏈創建的時候會插入一個索引為零,描述字符為" Genesis Block "的區塊,稱之為創始塊. 創世塊與其他塊的區別是交易的輸入與輸出,這個在後繼章節再詳細介紹。
AddBlock()與_GetLastBlock()相對比較簡單,_GetLastBlock()就是返回vector<Block> _vChain的最後一個元素。
AddBlock()就是通過挖礦產生一個區塊,放入到記錄vector<Block> _vChain中。當然要記得設置該塊的sPrevHash為之前區塊鏈中最後一個塊的哈希值.
Blockchain::Blockchain() { _vChain.emplace_back(Block(0, "Genesis Block")); _nDifficulty = DifficultyNum; } void Blockchain::AddBlock(Block bNew) { bNew.sPrevHash = _GetLastBlock().GetHash(); bNew.MineBlock(_nDifficulty); _vChain.push_back(bNew); } Block Blockchain::_GetLastBlock() const { return _vChain.back(); }
《build-a-blockchain-with-c》 的講解和VC工程的建立就到此為止。下面的章節我們將進行 《用 Go 構建一個區塊鏈》的c++化和內容的講解
cpp 區塊鏈模擬示例(二)工程代碼解析