位元幣原始碼解析 RPC詳解

2021-08-20 02:41:34 字數 4391 閱讀 8628

在這裡,我們暫時先拋開bitcoin**,僅僅來談rpc,提到rpc大家肯定首先會想到遠端過程服務呼叫,既然是呼叫,那就肯定存在乙個client端和乙個server端,clent端與server端通過rpc這個黑盒通過http請求進行互動,那麼就有乙個問題,我自定義的json格式的字串(這裡拿json來進行舉例)是無法在網路上流通的,所以,必然會涉及到乙個json的序列化與反序列化的過程。綜上所述,大致流程如下:

rpc命令的入口函式是從bitcoin-abc/src/rpc/register.h出發的,根據功能模組的不同,分了如下函式用來註冊rpc命令:

class

crpctable;

//區塊鏈rpc命令註冊

void

registerblockchainrpccommands

(crpctable &tablerpc)

;//p2p網路rpc命令註冊

void

registernetrpccommands

(crpctable &tablerpc)

;//其他工具rpc命令註冊

void

registermiscrpccommands

(crpctable &tablerpc)

;//挖礦rpc命令註冊

void

registerminingrpccommands

(crpctable &tablerpc)

;//交易prc命令註冊

void

registerrawtransactionrpccommands

(crpctable &tablerpc)

;//bch特有的rpc命令註冊

void

registerabcrpccommands

(crpctable &tablerpc)

;

首先來看crpctable這個類,它是乙個排程表變數,專門用來儲存rpc命令,它有乙個很重要的方法,如下:

bool

(const

std::string &name, const crpccommand *pcmd)

;

其他模組的rpc命令通過這個函式不斷追加到rpctable中。有兩個引數,乙個是rpc命令的名字name,另乙個是指向rpc command的乙個指標。

接下來我們看一下crpccommand這個類,它主要有如下定義:

std::string category;

std::string name;

rpcfn_type actor;

bool oksafemode;

std::vector

<:string> argnames;

它表示了當我需要新增加乙個rpc命令時,我這個新增加的命令需要描述如上所述的資訊。

下面,我們一起探索一下,各個模組都是怎麼註冊自己的rpc命令的,先看blockchain,具體如下:

static

const crpccommand commands = },

},},

},},

},};

篇幅有限,只列舉其中幾個。區塊鏈rpc命令在常量陣列commands中儲存,name就是我們在client中可以使用的rpc命令,那麼他是如何註冊到crpctable中的呢?

void

registerblockchainrpccommands

(crpctable &t)

}

註冊完成之後,當我們呼叫具體的某乙個rpc命令時,會發生什麼呢?我們拿blockchain中的getblockchaininfo來舉例,具體實現如下:

univalue getblockchaininfo(const config &config, const jsonrpcrequest &request)

lock(cs_main);

univalue obj(univalue::vobj);

obj.push_back(pair("chain", params().networkidstring()));

obj.push_back(pair("blocks", int(chainactive.height())));

obj.push_back(

pair("headers", pindexbestheader ? pindexbestheader->nheight : -1));

obj.push_back(

pair("bestblockhash", chainactive.tip()->getblockhash().gethex()));

obj.push_back(pair("difficulty", double(getdifficulty(chainactive.tip()))));

obj.push_back(

pair("mediantime", int64_t(chainactive.tip()->getmediantimepast())));

obj.push_back(

pair("verificationprogress",

guessverificationprogress(params().txdata(), chainactive.tip())));

obj.push_back(pair("chainwork", chainactive.tip()->nchainwork.gethex()));

obj.push_back(pair("pruned", fprunemode));

const consensus::params &consensusparams = params().getconsensus();

cblockindex *tip = chainactive.tip();

univalue softforks(univalue::varr);

univalue bip9_softforks(univalue::vobj);

softforks.push_back(softforkdesc("bip34", 2, tip, consensusparams));

softforks.push_back(softforkdesc("bip66", 3, tip, consensusparams));

softforks.push_back(softforkdesc("bip65", 4, tip, consensusparams));

bip9softforkdescpushback(bip9_softforks, "csv", consensusparams,

consensus::deployment_csv);

obj.push_back(pair("softforks", softforks));

obj.push_back(pair("bip9_softforks", bip9_softforks));

if (fprunemode)

obj.push_back(pair("pruneheight", block->nheight));

}return obj;

如上,每乙個rpc命令在他們相應的模組中,都有基於這個rpc所表述含義的相應**實現。

我們看到getblockchaininfo這個函式返回值是univalue,univalue是cpp中乙個json解析庫,用來將json格式的rpc命令轉化為網路可識別的。轉化實現主要在client.cpp

中進行了簡單的包裝,具體實現如下:

class

crpcconvertparam ;

我們會看到有時候會有相同的methodname,但是他們的paramidx不一樣,所代表的描述資訊也就不同,這裡要注意區分

clint.cpp主要是服務於bitcoin-cli

客戶端在這邊將json的命令進行序列化之後,傳送給對應的服務端(各個不同的模組),服務端在做相應的處理。

在protocol.h中,我們定義了一些http的狀態碼,以及rpc的錯誤碼,json的格式規範遵循的是rfc4627。

位元幣原始碼解析 3 準備知識 Boost

boost中test模組是用來給 做單元測試的,測試的方法是白盒測試,所以編寫測試必須對待測試的模組有深度的理解,然後再對正常功能和可能會出現的問題進行測試,測試的實際過程就是給定輸入判定是否和預期的輸出相同,所以test本質上也是個驗證等式的工具外加了一層包裝。測試過程中三個主要的工具是boost...

位元幣原始碼解析之初始化

本文主要描述了程序啟動時節點位址 區塊資訊和錢包資訊的初始化 節點執行緒和礦工挖礦執行緒在後續 位元幣原始碼解析之執行緒處理 一文中介紹,孤立塊處理在後續 位元幣原始碼解讀之挖礦 一文中介紹 初始化流程圖如下所示 1 首先呼叫caddrdb類的loadaddresses 函式 同時caddrdb的建...

位元幣原始碼解讀一

上次在ubuntu系統中將位元處原始碼編譯環境設定好了後,還沒有具體分析裡面的 今天我們就解讀一下。原始碼版本是bitcoin 0.9.5rc2。我們說驗證位元幣客戶端安裝成功就是從 which bitcoind 這個命令進行驗證的,因為位元幣客戶端有兩個。乙個是圖形介面的版本,通常被稱為 bitc...