<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                本章源代碼地址:[https://github.com/daleboy/blockchain3] # 前言 前面兩個版本的區塊鏈都是在內存中運行,本質上區塊鏈是一個分布式數據庫,我們在本版中只關注存儲,即將區塊鏈存儲到數據庫中,而分布式在后面的版本中實現。 # 數據選擇 比特幣選擇的數據庫是LevelDB,我們將選擇BoltDB: 1. 非常簡單和簡約 2. 用 Go 實現 3. 不需要運行一個服務器 4. 能夠允許我們構造想要的數據結構 BoltDB使用鍵值存儲,其API僅限于值的獲取或存儲。 BoltDB沒有數據類型,鍵和值都是字節數組(byte array),為了存儲區塊(Block),需要將struct序列化為byte array,取出時候,還需要將byte array反序列化為struct。 # 數據庫結構 數據庫結構決定了我們存儲什么到數據庫,以及存儲的形式。我們參考比特幣的數據庫結構: Bitcoin Core 使用兩個 “bucket” 來存儲數據: 1. 其中一個 bucket 是**blocks**,它存儲了描述一條鏈中所有塊的元數據 2. 另一個 bucket 是**chainstate**,存儲了一條鏈的狀態,也就是當前所有的未花費的交易輸出,和一些元數據 此外,出于性能的考慮,Bitcoin Core 將每個區塊(block)存儲為磁盤上的不同文件。如此一來,就不需要僅僅為了讀取一個單一的塊而將所有(或者部分)的塊都加載到內存中。但是,為了簡單起見,我們并不會實現這一點。 因為目前還沒有交易,所以我們只需要**blocks**bucket。另外,正如上面提到的,我們會將整個數據庫存儲為單個文件,而不是將區塊存儲在不同的文件中。所以,我們也不會需要文件編號(file number)相關的東西。最終,我們會用到的鍵值對有: 1. 32 字節的 block-hash -> block 的結構,目的性不言而喻 2. 鏈中最后一塊的hash,目的是為了挖新區塊時候需要用到 # 序列化 我們用[encoding/gob](https://link.jianshu.com/?t=https://golang.org/pkg/encoding/gob/)來完成序列化。 ![](https://img.kancloud.cn/63/f2/63f29d0d8e5e933e635084b30c034096_1147x932.png) 這里需要注意,由于在go中,struct是一個值類型,所以創建實例時候直接按值類型的方式創建,而為了更好利用內存,通過引用(指針)來使用實例(無論是作為函數的左值還是作為函數的參數)。 # 持久化 持久化在blockchain.go之中實現,從NewBlockchain改造開始: 1. 打開一個數據庫文件 2. 檢查文件里面是否已經存儲了一個區塊鏈 3. 如果已經存儲了一個區塊鏈: 1. 創建一個新的`Blockchain`實例 2. 設置`Blockchain`實例的 tip 為數據庫中存儲的最后一個塊的哈希 4. 如果沒有區塊鏈: 1. 創建創世塊 2. 存儲到數據庫 3. 將創世塊哈希保存為最后一個塊的哈希 4. 創建一個新的`Blockchain`實例,其 tip 指向創世塊(tip 有尾部,尖端的意思,在這里 tip 存儲的是最后一個塊的哈希) ![](https://img.kancloud.cn/dc/b7/dcb7cb8dfb5fdce751f5f28a73f492d9_2003x1508.png) 注意的是,存儲到數據庫的最后一個區塊的哈希鍵值對:鍵為字符串"1"的二進制數組,值為哈希值的二進制數組。 ## 區塊鏈結構 ![](https://img.kancloud.cn/c6/6a/c66a8ccdc1f199eefe31492522e8fe25_1224x259.png) 序列化后,新的區塊鏈結構不再存儲所有的區塊,而只存儲區塊鏈最后一個區塊的哈希(tip),另外,存儲了一個數據庫連接,這樣方便后面隨時使用。 ## AddBlock 將普通區塊存入數據庫比較簡單: 1. 從數據庫讀取最后一個區塊的哈希; 2. 挖出符合要求的區塊; 3. 將新區塊寫入數據庫表; 4. 修改數據庫表中的tip; 5. 更新當前區塊實例的tip。 ![](https://img.kancloud.cn/71/36/713652cdcfdee3537ae4bd10bf8db7d5_1438x1174.png) # 區塊鏈迭代器 使用區塊鏈迭代器的好處是,我們在讀取區塊鏈中的區塊時候,不必將所有的塊都加載到內存中(因為我們的區塊鏈數據庫可能很大!或者現在可以假裝它可能很大),而是一個一個地讀取它們。 ![](https://img.kancloud.cn/bd/a4/bda46cbe26086d1a5ea7feae59644a7e_1148x1147.png) 實際上,**選擇一個 tip 就是意味著給一條鏈“投票”**。一條鏈可能有多個分支,最長的那條鏈會被認為是主分支。在獲得一個 tip (可以是鏈中的任意一個塊)之后,我們就可以重新構造整條鏈,找到它的長度和需要構建它的工作。這同樣也意味著,一個 tip 也就是區塊鏈的一種標識符。 # CLI命令行 到目前為止,我們的實現還沒有提供一個與程序交互的接口:目前只是在`main`函數中簡單執行了`NewBlockchain`和`bc.AddBlock`。是時候改變了!現在我們想要擁有這些命令: ~~~ blockchain_go addblock "Pay 0.031337 for a coffee" blockchain_go printchain ~~~ CLI的具體實現在cli.go中,見github。 # main.go 是時候檢驗我們的目標是否實現了: ![](https://img.kancloud.cn/df/c3/dfc3381b0475c8302d30eea221dae351_1049x258.png) 注意,struct實例化的寫法: (1)以key:value的方式構建struct實例是更嚴謹的寫法 (2)如果是在包內使用,直接寫value是可以的 (3)如果在包外使用,直接寫value會出錯:composite?literal?uses?unkeyed?fields 注意,在命令行執行前,區塊鏈已經創建好了,當然創始區塊也挖好了。 運行結果: ![](https://img.kancloud.cn/23/c3/23c3e9425316cff993735063a997de6b_1007x452.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看