當前位置:
首頁 > 科技 > 教你用C+搭建一條迷你區塊鏈!

教你用C+搭建一條迷你區塊鏈!

本文作者:陳浩,國內領先公有鏈元界 CTO,極客時間「深入淺出區塊鏈」出品人。

程序員的天賦技能就是通過代碼實踐自己的想法,完成一個作品會有相當的成就感,所以今天我們以 C++14 的代碼為例子,和你分享設計並實現一個迷你區塊鏈例子。

目標和範圍

首先我們要知道達成的目標,根據目標劃定工作範圍。

考慮到我們無法搭建一個類似比特幣的龐大 P2P 網路,也沒有太多精力實現一個真正意義上的完整功能的全節點錢包,而且完整的全節點過於複雜,會讓學習者迷失在細節中。

所以我們的目標是:構建一個包含僅基礎功能的全節點客戶端,它可能沒有太炫酷的 UI 頁面,也沒有複雜的命令,僅一個命令行工具和一個全節點核心程序,它們提供下面的功能。

提供 P2P 節點發現和同步區塊的功能;

提供創建公私鑰對的功能;

提供發送交易的功能;

提供交易查詢的功能;

提供餘額查詢的功能;

提供挖礦的功能,在任意地址商都可以發起單機挖礦;

提供基礎日誌,方便跟蹤監視。

以上 7 個功能基本涵蓋了一個區塊鏈全節點的主要功能,但是,由於篇幅有限,代碼不能全部實現,主要講解設計和實現思路。後續我會逐漸完善代碼,你也可以一起參與,代碼開源在:https://github.com/betachen/tinychain

技術選型

我們在「深入淺出區塊鏈」專欄中說到過,區塊鏈的四個核心技術概念:P2P 網路、賬戶模型與存儲、共識、加密模塊。

戳此可訂閱「深入淺出區塊鏈」專欄

首先,P2P 網路模塊是區塊鏈的最底層模塊之一,我們主要考慮方便實現和測試,可選的方案有輕量級消息隊列和 WebSocket。考慮到集成的便利性,我們首選 WebSocket,因為至少需要一個 HTTP JSON-RPC Server,我們可以復用 Server 中的 Websocket 服務。

除了通訊協議之外,還要考慮數據交換格式,我們考慮採用易讀通用的 JSON 格式,而不是像比特幣一樣的數據序列化格式,後期更改可以考慮升級到 Protobuf,後者優勢主要體現在性能上。而在我們的例子中,性能永遠不是首先考慮的,更多是它的易讀和易調試性。

其次,我們來說說賬戶加密部分,由於 ECDSA 非對稱加密模塊過於複雜,我們選用 OpenSSL 庫中的 RSA 演算法作為加密模塊。而交易模型上,我們考慮使用 UTXO 模型,因為狀態模型需要維護狀態,可能會帶來額外的代碼複雜度。

再來說說資料庫存儲,這個模塊需要考慮到易用性和易讀性,我們選用 SQLite 3 作為持久化存儲。

最後來談談共識演算法這一模塊,我們選用 PoW 作為共識演算法,考慮到 PoW 最為簡單實現,而且交易和區塊的哈希計算會涉及到 SHA-256,使用 PoW 演算法我們就可以復用 SHA-256 的代碼,所以使用 SHA-256 演算法作為挖礦演算法會降低我們的工作量。

詳細功能

有了技術選型之後,我們再對目標功能點進行細分拆解。

P2P 網路:節點發現、節點維護、持久化保存、區塊同步。

公私鑰對:命令行、創建公私鑰對、並生成地址、提供私鑰存儲、公私鑰驗證。

發送交易:命令行、發送成功驗證、輸入是交易哈希。

交易查詢:命令行、JSON 格式的交易查詢返回、輸入是某個地址。

餘額查詢:命令行、JSON 格式的餘額查詢返回、輸入是某個地址。

挖礦:命令行、JSON 格式挖礦信息返回、輸入是某個地址。

區塊共識:編織區塊鏈的演算法,包含創世區塊以及調整全網挖礦難度。

交易共識:驗證單個交易的演算法,包含簽名驗證和 UTXO 驗證。

基礎日誌:用於監控網路、區塊驗證等操作。

區塊持久化存儲:分叉與合併時的一致性,並為查詢提供介面。

提供格式化輸出交易的功能,這裡的格式化主要指 JSON 格式。

有效防止雙花交易。

通過詳細的功能拆分我們可以發現,功能點多達三十餘個,如何設計實現這三十多個功能點是我們接下來首先要解決的問題。問題是這三十多個功能點不是孤立的,而是有相互聯繫的,我們先從頂層開始設計。

最頂層是一個區塊節點,一個完整的可執行程序,我們命名為 tinychain,而對應的命令行客戶端為 cli-tinychain。

Tinychain 的核心程序主要包含以下結構:

我們以 node 為最頂層,那麼 node 會包含其他五個模塊,node 啟動就會把其他 5 個服務啟動。

cli-tinychain 主要包含以下結構:

命令行就簡單多了,我們把命令行的執行和計算全部都扔到 tinychian 當中,命令行只用一個 http-client 用 JSON 把 API 包起來即可。

通過分析我們知道,以下組件是必不可少的,但是我們不必自己開發,可以直接選取一些現成的開發包直接集成即可。

區塊數據結構設計

有了大致的頂層設計已經分類好,那麼接下來我們考慮為每個模塊填充一些數據結構。一個區塊鏈最重要的是區塊,所以我們從區塊開始。

一個區塊包含兩部分,分別是區塊頭和區塊體,區塊頭是一個區塊的元數據,區塊體就是包含交易的列表,所以我們直接設計交易體。

區塊頭的設計

我們參照比特幣的設計,區塊頭包含了前向區塊哈希、默克爾根哈希、時間戳、難度目標、Nonce 值和版本號。

所以我們的結構可能是這樣的:

target_bits 表示當前區塊的目標值;

hash 表示這個區塊的哈希;

merkle_tree_hash 表示這個區塊當中交易列表的默克爾根;

nonce 表示隨機數;

height 表示當前區塊的高度;

previous_block_hash 指向前向區塊哈希;

time_stamp 表示生產這個區塊時的時間戳;

transaction_count 表示這個區塊當中包含多少筆交易;

version 表示區塊的版本號,不代表交易的版本號。

在這裡,我們的區塊頭大小不是固定的,因為它沒有經過序列化,完全以 JSON 表示,所以我們這裡就不考慮位元組印第安序的問題了,也不考慮固定長度的問題。

有了區塊頭,我們再看看交易體的設計,由於使用 utxo 作為交易模型,那麼我們先考慮一個輸入一個輸出的結構。

我們可以按照這種結構來設計交易體。

地址設計

區塊鏈地址都有通常意義上的地址,我們這裡將公鑰直接算作地址,不再將公鑰進行哈希轉換。

內存池

內存池是指緩存交易的一塊交易緩衝區,這裡一個節點的主要處理對象,所以對內存池的管理,是編織區塊鏈的最重要一步。我們這裡的內存池使用標準庫 STL 中的容器。

哈希計算

區塊和交易的哈希計算均使用 SHA-256。

開發環境搭建

由於選取了 C++ 作為實現方式,搭建工程的過程會比較複雜一點。我們用的是 Ubuntu 16.04 開發環境,默認的 gcc 編譯器是 gcc-5.4,是支持 C++14 標準的。代碼也是全平台可移植的,如果你使用 Mac,也可以嘗試搭建。

除了 gcc 之外,我們還需要 Cmake 來構建工程。我們也許需要 Boost 庫的支持,例如 Filesystem 和 Datetime 等基礎組件。

所以我們的工具鏈是:

gcc 或 clang

cmake

boost 1.56+ (datetime)

最後我們還需要一個簡單好用的輕量級 Httpserver,我選取了元界代碼中的 Mongoose 庫,這裡的 Mongoose 不是 MongoDB,是由 Cesanta 開源的一個 HTTP Server 庫,支持 epoll 和 select 兩種網路並發機制,也支持 WebSocket。

當然除了 C++ 實現之外,我們也可以使用 Python 來實現,實際上也有不少 Python 實現的 Demo,但我發現用 Python 實現的例子很多是在單進程中模擬區塊鏈的數據結構,並不是真正意義上的分散式節點,所以我採取了自己使用 C++ 實現的策略。

測試環境搭建

我們知道區塊鏈是一個分散式網路環境,在開始之前,我們需要構造一個簡單且容易測試的分散式網路環境。

我們不可能購買大量的雲計算資源,所以我們推薦你購買一個基礎版的 ECS 節點,2Core 4G 就可以,性能稍好更好,接著我們選用 Docker 來搭建容器集群,在容器中部署節點,其中宿主機作為編譯環境,將編譯完成的錢包部署到全部的 Docker 容器中。

總結

今天大致介紹了實踐一個迷你區塊鏈的思路,我們先劃定了實踐的範圍,接著考慮了技術選型,然後細化了詳細功能,考慮了一個區塊鏈需要的數據結構,最後考慮了開發環境和測試環境的搭建。

本文出自極客時間「深入淺出區塊鏈」專欄。國內區塊鏈項目 Metaverse 元界 CTO 陳浩,帶你少做彎路地入門區塊鏈,通過通俗易懂的語言從 0 開始,教你掌握區塊鏈的基礎知識,構建區塊鏈體系架構,梳理區塊鏈學習路徑。

限時拼團

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 InfoQ 的精彩文章:

如何成為互聯網時代的優秀測試架構師?eBay測試老兵告訴你
迅雷創始人程浩:流量、資本紅利已成過去式,中國互聯網下一個十年屬於……

TAG:InfoQ |