1. 程式人生 > >cpp 區塊鏈模擬示例(二)工程代碼解析

cpp 區塊鏈模擬示例(二)工程代碼解析

string 組成 記錄 代碼 相對 int32 return 對比 速度

書接上文

我們先來看區塊的結構

 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 區塊鏈模擬示例(二)工程代碼解析