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