C语言实现的ABCI
本文主要介紹用 C 語言實現的 Tendermint ABCI,以及如何在此之上構建一個屬于自己的應用
原文作者:許莉
英文版本:C-ABCI
簡介
首先簡單介紹一下 Tendermint 和 ABCI。
Tendermint 的核心就是共識引擎,它主要負責兩點:
- 節點之間共享交易和區塊
- 建立一個規范且不可改變的交易順序(也就是區塊鏈)
ABCI(Application BlockChain Interface)是 Tendermint 與應用程序之間的一個接口,它可以使用各種語言來實現。目前已經實現的語言有?C++,JavaScript,Java和?Erlang,尚無 C 語言實現,故而本文實現了 C 版本的 ABCI。
如果對于 Tendermint 和 ABCI 尚不熟悉,或者想要了解更多有關內容,可自行參閱以下資料:
- Tendermint Intro
- ABCI Overview
- Tendermint Intro 中文翻譯
C-ABCI 的GitHub源碼:chainx-org/c-abci。
運行示例
安裝 Tendermint
在編譯啟動 C-ABCI 之前,首先需要安裝 Tendermint,這里是官方的安裝指南。
編譯執行 c-dummy
Tendermint 安裝完成之后,從 GitHub 下載 C-ABCI 源碼到本地:
| 1 | git clone https://github.com/chainx-org/c-abci.git ~/c-abci |
進入到目錄 c-abci ,執行?make?對源碼進行編譯:
| 1 2 | cd ~/c-abci make |
編譯成功, 可以看到如下信息:
編譯完成后,會在 bin 目錄下生成一個叫做 c-dummy 的可執行程序,執行該程序:
| 1 2 | cd bin ./c-dummy |
啟動 Tendermint
c-dummy 啟動后,開始啟動 Tendermint。如果是首次執行Tendermint,需要先進行初始化再啟動節點
| 1 2 | tendermint init tendermint node |
如果之前有啟動過 Tendermint,先對 Tendermint 進行重置再啟動節點:
| 1 2 | tendermint unsafe_reset_all tendermint node |
這就是整個啟動過程了,下面有個C-ABCI啟動過程的視頻:
代碼架構
Tendermint 提供了 GRPC 和 TSP 兩種通信方式,C-ABCI 使用了后者,用基于 TCP 協議的 Socket 來完成通信模塊。Tendermint 會保持3個連接:內存池連接(Mempool Connection)、共識連接(Consensus Connection)、查詢連接(Query Connection),三個連接簡介。在 C-ABCI 的實現中,每個連接都擁有一個獨立的進程來專門處理此連接的所有請求,后期可能會增加用獨立線程來處理的版本。
前面提到 ABCI 是一個接口,對 C 語言來說,它其實就是一個庫。C-ABCI 就是一個用 C 語言實現的庫,應用程序調用這個庫來與 Tendermint 進行數據交互。C-ABCI 對于 Tendermint 與應用程序之間通信的具體數據并不感興趣,它只是作為一個傳遞者而已!C-ABCI 與 Tendermint 之間數據的傳輸是通過 TCP Socket 來實現的,與應用程序之間數據的傳輸則是通過回調函數來實現的。
應用程序、C-ABCI、Tendermint 三者之間處理流程:
C-ABCI 源碼中,一共有 7 個目錄,除了?include?目錄之外每個目錄都代表著一個模塊,對于?socket,encoding,dlist?三個目錄,是完全獨立的,可以移出來放在任何項目中使用,后期有時間會把這三個獨立的模塊抽取出來繼續完善!
下面具體說明一下每個目錄的作用:
| include | 頭文件目錄,包含所有模塊的頭文件 |
| socket | 通信模塊,主要功能是實現TCP協議的通信,提供了綁定監聽端口,連接端口,關閉端口,以及接收,發送數據的接口 |
| encoding | 字符轉換模塊,主要功能是實現大小端整型數據與字符串之間的轉換,分別提供了大端和小端不同位數的無符號整型與無符號字符串之間互相轉換的接口 |
| dlist | 數據存儲模塊,主要功能是使用循環雙向鏈表來實現數據的存儲,提供了鏈表的創建,銷毀,增加,刪除,查找接口 |
| type | 數據類型處理模塊,主要功能是實現數據結構體的的相關操作,提供結構體的創建,銷毀等接口。Tendermint使用的數據類型保存在一個types.proto文件中,使用第三方軟件protobuf-c軟件將此文件生成C文件格式 |
| core | C-ABCI的核心模塊,主要功能就是實現一個服務端,給應用程序提供了初始化服務,開始服務以及停止服務的接口 |
| demo | 實現了一個簡單的應用程序,關于數據存儲使用了dlist模塊。 |
應用程序示例
在 C-ABCI 的源碼中,demo?目錄中實現了一個簡單的應用程序,可以參考這個應用程序來實現自己的應用程序。
C-ABCI中有多個目錄,但是編寫一個應用程序不用每個目錄都需要去了解,只需要了解:
- core:核心模塊
- type:數據類型處理模塊
下面結合?demo?講述一下如何使用上面所說的兩個模塊在 C-ABCI 上編寫一個屬于自己的應用程序。
應用程序的?main?函數中只需要調用?core?提供的三個接口,就完成了整個框架的編寫(對照?demo?中?main.c理解)
初始化C-ABCI服務
此接口是綁定和監聽傳入的IP地址和端口
| 1 | int server_init(const char *ipaddr, const char *port); |
啟動C-ABCI服務
只要沒有出錯,此接口不會返回,會一直等待新的連接,傳入的app參數就是由應用程序實現的回調函數
| 1 | int server_start(Application app) |
停止C-ABCI服務
此接口主要是關閉監聽的端口
| 1 | void server_stop(); |
這樣,應用程序的框架代碼就已經完成了。剩下所需要做的事情就是實現回調函數了,回調函數的實現:(demo中的dummy.c):
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | void *ABCIApplication(Types__Request *request) { switch( request->value_case ) { case TYPES__REQUEST__VALUE_INFO: return Info(); case TYPES__REQUEST__VALUE_SET_OPTION: return SetOption(request->set_option); case TYPES__REQUEST__VALUE_DELIVER_TX: return DeliverTx(request->deliver_tx); case TYPES__REQUEST__VALUE_CHECK_TX: return CheckTx(request->check_tx); case TYPES__REQUEST__VALUE_COMMIT: return Commit(); case TYPES__REQUEST__VALUE_QUERY: return Query(request->query); case TYPES__REQUEST__VALUE_INIT_CHAIN: return InitChain(request->init_chain); case TYPES__REQUEST__VALUE_BEGIN_BLOCK: return BeginBlock(request->begin_block); case TYPES__REQUEST__VALUE_END_BLOCK: return EndBlock(request->end_block); } } |
每個應用程序回調函數的實現都是如此。回調函數的參數是由 C-ABCI 提供,根據不同的請求會有不同的具體實現函數,這些具體實現函數就是應用程序代碼編寫的重點了,也就是應用程序的業務處理的邏輯代碼。業務邏輯代碼寫完,那么一個應用程序就完成了,剩下的就是編譯運行了!
在?demo?中只實現了個別請求的具體實現,邏輯代碼也非常的簡單的,只是將請求的數據保存起來而已!demo 中對于數據存儲這一塊使用的是循環雙向鏈表(?dlist?模塊),應用程序可以不用使用C-ABCI提供的數據存儲模塊(dlist),可以選擇其他的數據存儲技術,比如樹,數據庫等等!
GitHub Wiki:C-ABCI編譯運行出現的問題
原始鏈接:https://lilymoana.github.io/Chi_C-ABCI.html?
總結
以上是生活随笔為你收集整理的C语言实现的ABCI的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DPOS共识算法—缺失的白皮书
- 下一篇: 以太坊的工作原理