cpp 區塊鏈模擬示例(五) 序列化

有了區塊和區塊鏈的基本結構,有了工做量證實,咱們已經能夠開始挖礦了。剩下就是最核心的功能-交易,可是在開始實現交易這一重大功能以前,咱們還要預先作一些鋪墊,好比數據的序列化和啓動命令解析。c++

根據用 Go 構建一個區塊鏈》的目錄, 本章節的區塊數據的序列化存儲會使用一款KV數據庫。其中比特幣中是使用的是谷歌出品、c++編寫的 LevelDB數據庫,go語言示例中使用的是BoltDB。git

我原本考慮使用redis和json來進行咱們的數據序列化存儲。使用boost庫的program_options 解析命令行參數。可是考慮代碼過於複雜也許會偏離演示區塊鏈的屬性這一目的。最後進行了精簡,最終的方案是捨去命令行參數解析,數據序列化改成使用map容器做爲哈希與區塊block指針的映射記錄。github

咱們代替序列化的數據結構爲map<string, Block*> g_db;redis

該結構是一個哈希值與區塊指針的映射,因爲每一個區塊的哈希值的都是獨一無二的,必定程度上哈希就至關於KV數據庫中KEY。數據庫

咱們經過獨一無二的哈希值能夠快速的map容器中查找的到區塊指針,這一過程與使用kv數據的增刪改查接口是基本相同的。因此使用map能達到使用kv數據同樣的演示效果。json

一 建立區塊鏈與加入創世塊

讓咱們從 NewBlockchain 函數開始。在以前的實現中,它會建立一個新的 Blockchain 實例,並向其中加入創世塊。而如今,咱們但願它作的事情有數組

  1. 建立創世塊
  2. 存儲到map中
  3. 將創世塊哈希保存爲最後一個塊的哈希
  4. 建立一個新的 Blockchain 實例,其 tip 指向創世塊(tip 有尾部,尖端的意思,在這裏 tip 存儲的是最後一個塊的哈希
    代碼大概是這樣:
 1 Blockchain* NewBlockchain() {
 2     string tip;
 3     Block* genesis = NewGenesisBlock();
 4     g_db[genesis->hash] = genesis;
 5     g_db["l"] = genesis;
 6     tip = genesis->hash;
 7 
 8     Blockchain* bc = new Blockchain{ tip, &g_db };
 9 
10     return bc;
11 }

咱們建立了一個創世塊,而且記錄到全局map中,創始塊哈希映射創始塊的指針。 「l」字符串映射目前最後一個區塊指針,剛好也是目前惟一的一個區塊-創世塊。 tp記錄最後一個區塊的哈希,也是目前惟一的一個區塊-創世塊的哈希數據結構

Blockchain 的結構如今看起來是這樣:函數

typedef struct blockchain {
    string tip;
    map<string, Block*>* db;
}Blockchain;

接下來咱們想要更新的是 AddBlock 方法:如今向鏈中加入區塊,就不是像以前向一個數組中加入一個元素那麼簡單了。從如今開始,咱們會將區塊存儲在數據庫裏面:post

void AddBlock(string  data, Blockchain* bc) {
    string lastHash;

    Block* p = g_db["l"];
    if (p == NULL)
        return;
    lastHash = p->hash;

    Block* newBlock = NewBlock(data, lastHash);

    (*bc->db)[newBlock->hash] = newBlock;
    (*bc->db)["l"] = newBlock;

    bc->tip = newBlock->hash;
}

 

二檢查區塊鏈

如今,產生的全部塊都會被保存到一個數據庫裏面,因此咱們能夠從新打開一個鏈,而後向裏面加入新塊。可是在實現這一點後,咱們失去了以前一個很是好的特性:咱們再也沒法打印區塊鏈的區塊了,由於如今不是將區塊存儲在一個數組,而是放到了數據庫裏面。讓咱們來解決這個問題!

BoltDB 容許對一個 bucket 裏面的全部 key 進行迭代,可是全部的 key 都以字節序進行存儲,並且咱們想要以區塊可以進入區塊鏈中的順序進行打印。此外,由於咱們不想將全部的塊都加載到內存中(由於咱們的區塊鏈數據庫可能很大!或者如今能夠僞裝它可能很大),咱們將會一個一個地讀取它們。故而,咱們須要一個區塊鏈迭代器(BlockchainIterator):

typedef struct blockchainiterator {
    string currentHash;
    map<string, Block*>* db;
}BlockchainIterator;

每當要對鏈中的塊進行迭代時,咱們就會建立一個迭代器,裏面存儲了當前迭代的塊哈希(currentHash)和數據庫的鏈接(db)。經過 db,迭代器邏輯上被附屬到一個區塊鏈上(這裏的區塊鏈指的是存儲了一個數據庫鏈接的 Blockchain 實例),而且經過 Blockchain 方法進行建立:

BlockchainIterator* Iterator(Blockchain* bc) {
    BlockchainIterator* bci = new BlockchainIterator{ bc->tip,bc->db };
    return bci;
}

注意,迭代器的初始狀態爲鏈中的 tip,所以區塊將從頭至尾,也就是從最新的到最舊的進行獲取。實際上,選擇一個 tip 就是意味着給一條鏈「投票」。一條鏈可能有多個分支,最長的那條鏈會被認爲是主分支。在得到一個 tip (能夠是鏈中的任意一個塊)以後,咱們就能夠從新構造整條鏈,找到它的長度和須要構建它的工做。這一樣也意味着,一個 tip 也就是區塊鏈的一種標識符。

BlockchainIterator 只會作一件事情:返回鏈中的下一個塊

Block* Next(BlockchainIterator* i){
    Block* block;
    if (i->currentHash == "")
        return NULL;
    block = (*i->db)[i->currentHash];
    i->currentHash = block->prevBlockHash;
    return block;
}

這就是數據庫部分的內容了!

 

咱們在main函數中測試建立區塊鏈和添加區塊 而且打印結果 代碼以下

int main()
{
    Blockchain* bc = NewBlockchain();
    printChain(bc);

    AddBlock("Send 1 BTC to Ivan", bc);
    printChain(bc);

    AddBlock("Pay 0.31337 BTC for a coffee", bc);
    printChain(bc);

    return 0;
}

運行結果以下:

 

 

Mining the block containing Genesis Block


Prev. hash:
Data: Genesis Block
Hash: 000000e8b0be7b9518b23c6cfbfc7ff19ec8395141e37cfdb87e7e448cf1d8c0

Mining the block containing Send 1 BTC to Ivan


Prev. hash: 000000e8b0be7b9518b23c6cfbfc7ff19ec8395141e37cfdb87e7e448cf1d8c0
Data: Send 1 BTC to Ivan
Hash: 0000005abaa800aba85a0d0ae8bd11077af9bfdf41cbc96c217638b6990988aa

Prev. hash:
Data: Genesis Block
Hash: 000000e8b0be7b9518b23c6cfbfc7ff19ec8395141e37cfdb87e7e448cf1d8c0

Mining the block containing Pay 0.31337 BTC for a coffee


Prev. hash: 0000005abaa800aba85a0d0ae8bd11077af9bfdf41cbc96c217638b6990988aa
Data: Pay 0.31337 BTC for a coffee
Hash: 000000401cdc481e2c6698a801917e65dbc1ab0168aed077feef04623f8e1280

Prev. hash: 000000e8b0be7b9518b23c6cfbfc7ff19ec8395141e37cfdb87e7e448cf1d8c0
Data: Send 1 BTC to Ivan
Hash: 0000005abaa800aba85a0d0ae8bd11077af9bfdf41cbc96c217638b6990988aa

Prev. hash:
Data: Genesis Block
Hash: 000000e8b0be7b9518b23c6cfbfc7ff19ec8395141e37cfdb87e7e448cf1d8c0

請按任意鍵繼續. . .

 

 

 工程代碼見羣下載  文件名爲CppBlockchain_part3.zip

 

參考博文:

https://blog.csdn.net/simple_the_best/article/details/78157303

https://jeiwan.cc/posts/building-blockchain-in-go-part-3/

相關文章
相關標籤/搜索