日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tendermint源码解析

發(fā)布時間:2023/12/31 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tendermint源码解析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、最基礎的默認配置
源碼文件:tendermint/tendermint/config/config.go

// NOTE: Most of the structs & relevant comments + the // default configuration options were used to manually // generate the config.toml. Please reflect any changes // made here in the defaultConfigTemplate constant in // config/toml.go // NOTE: tmlibs/cli must know to look in the config dir! var (DefaultTendermintDir = ".tendermint"defaultConfigDir = "config"defaultDataDir = "data"defaultConfigFileName = "config.toml"defaultGenesisJSONName = "genesis.json"defaultPrivValName = "priv_validator.json"defaultNodeKeyName = "node_key.json"defaultAddrBookName = "addrbook.json"defaultConfigFilePath = filepath.Join(defaultConfigDir, defaultConfigFileName)defaultGenesisJSONPath = filepath.Join(defaultConfigDir, defaultGenesisJSONName)defaultPrivValPath = filepath.Join(defaultConfigDir, defaultPrivValName)defaultNodeKeyPath = filepath.Join(defaultConfigDir, defaultNodeKeyName)defaultAddrBookPath = filepath.Join(defaultConfigDir, defaultAddrBookName) )

這里定義了tendermint的默認配置存放的目錄和文件名,在執(zhí)行tendermint的init命令時會調(diào)用。
二、生成默認配置文件
命令:

tendermint init

源碼文件:tendermint/cmd/tendermint/commands/init.go
觸發(fā)的函數(shù)調(diào)用關(guān)系
initFiles -> initFilesWithConfig
結(jié)果生成兩個配置文件:
private validator
genesis file
node_key.json
三、核心配置文件
config.toml由tendermint node命令生成
源碼文件:
tendermint/cmd/tendermint/main.go
tendermint/cmd/tendermint/commands/root.go
tendermint/config/toml.go
調(diào)用關(guān)系:
main() -> RootCmd -> ParseConfig() -> EnsureRoot() -> writeDefaultConfigFile() -> DefaultConfig()

// Write default config file if missing.if !cmn.FileExists(configFilePath) {writeDefaultConfigFile(configFilePath)}

tendermint每次運行時,都會檢查config.toml,找不到就會自動生成一個。
四、編譯文件

var _ types.Application = (*PersistentKVStoreApplication)(nil)

這句代碼的作用強制轉(zhuǎn)換一個空指針到一個unused的變量。
官方注釋(看不懂)

// This is a compile-time assertion to ensure that this generated file // is compatible with the proto package it is being compiled against. // A compilation error at this line likely means your copy of the // proto package needs to be updated.

GOLANG注釋

This post is about a little-known way to make compile-time assertions in Go. You probably shouldn’t use it, but it is interesting to know about.As a warm-up, here’s a fairly well-known form of compile-time assertions in Go: Interface satisfaction checks.In this code (playground), the var _ = line ensures that type W is a stringWriter, as checked for by io.WriteString.

五、RPC測試
1.RPC配置
源碼文件:tendermint/config/config.go

type RPCConfig struct {RootDir stringUnsafe bool ListenAddress string GRPCListenAddress string MaxOpenConnections int GRPCMaxOpenConnections int }

Unsafe是針對ListenAddress和GRPCListenAddress都起作用的配置項。ListenAddress和GRPCListenAddress的關(guān)系一看就是完全對等的。既然這兩種連接是對等的,那么MaxOpenConnections和GRPCMaxOpenConnections也應該是獨立計數(shù)的。

從源碼看出,ListenAddress在社區(qū)中稱為RPC,支持兩種協(xié)議,Http和Websocket,這兩種協(xié)議可以共用一個端口,源于websockt與 HTTP 協(xié)議有著良好的兼容性,tendermint中使用一個特殊的路徑來做區(qū)分,下面是部分源碼。

mux := http.NewServeMux() wm := rpcserver.NewWebsocketManager(rpccore.Routes, coreCodec, rpcserver.EventSubscriber(n.eventBus))wm.SetLogger(rpcLogger.With("protocol", "websocket"))mux.HandleFunc("/websocket", wm.WebsocketHandler)

2.RPC測試
tendermint在連接ABCI服務端的時候,扮演的是一個客戶端;當JSON-RPC連接tendermint的時候扮演的是一個服務端的角色。
Tendermint 支持下面三種RPC協(xié)議:

  • URI over HTTP
  • JSONRPC over HTTP
  • JSONRPC over websockets
    同時,tendermint也提供了GRPC監(jiān)聽接口,下面是相關(guān)代碼
func (n *Node) startRPC() ([]net.Listener, error) {n.ConfigureRPC()listenAddrs := splitAndTrimEmpty(n.config.RPC.ListenAddress, ",", " ")coreCodec := amino.NewCodec()ctypes.RegisterAmino(coreCodec)if n.config.RPC.Unsafe {rpccore.AddUnsafeRoutes()}// we may expose the rpc over both a unix and tcp socketlisteners := make([]net.Listener, len(listenAddrs))for i, listenAddr := range listenAddrs {mux := http.NewServeMux()rpcLogger := n.Logger.With("module", "rpc-server")wm := rpcserver.NewWebsocketManager(rpccore.Routes, coreCodec, rpcserver.EventSubscriber(n.eventBus))wm.SetLogger(rpcLogger.With("protocol", "websocket"))mux.HandleFunc("/websocket", wm.WebsocketHandler)rpcserver.RegisterRPCFuncs(mux, rpccore.Routes, coreCodec, rpcLogger)listener, err := rpcserver.StartHTTPServer(listenAddr,mux,rpcLogger,rpcserver.Config{MaxOpenConnections: n.config.RPC.MaxOpenConnections},)if err != nil {return nil, err}listeners[i] = listener}// we expose a simplified api over grpc for convenience to app devsgrpcListenAddr := n.config.RPC.GRPCListenAddressif grpcListenAddr != "" {listener, err := grpccore.StartGRPCServer(grpcListenAddr,grpccore.Config{MaxOpenConnections: n.config.RPC.GRPCMaxOpenConnections,},)if err != nil {return nil, err}listeners = append(listeners, listener)}return listeners, nil }

從代碼注釋可以看出,目前gRPC接口只是用來方便開發(fā)者,并不帶算實際生產(chǎn)中使用。
交易流程
在我們調(diào)用 broadcast_tx_commit 的時候,會先調(diào)用 CheckTx,驗證通過后會把 TX 加入到 mempool 里。在 kvstore 示例中沒有對 transaction 做檢查,直接通過:

func (app *KVStoreApplication) CheckTx(tx []byte) types.ResponseCheckTx {return types.ResponseCheckTx{Code: code.CodeTypeOK} }

放到 mempool 里的 TX 會被定期廣播到所有節(jié)點。當 Tendermint 選出了 Proposal 節(jié)點后,它便會從 mempool 里選出一系列的 TXs,將它們組成一個 Block,廣播給所有的節(jié)點。節(jié)點在收到 Block 后,會對 Block 里的所有 TX 執(zhí)行 DeliverTX 操作,同時對 Block 執(zhí)行 Commit 操作。
我們調(diào)用 broadcast_tx_commit 返回的結(jié)果其實就是 DeliverTX 返回的結(jié)果

func (app *KVStoreApplication) DeliverTx(tx []byte) types.ResponseDeliverTx {var key, value []byteparts := bytes.Split(tx, []byte("="))if len(parts) == 2 {key, value = parts[0], parts[1]} else {key, value = tx, tx}app.state.db.Set(prefixKey(key), value)app.state.Size += 1tags := []cmn.KVPair{{[]byte("app.creator"), []byte("jae")},{[]byte("app.key"), key},}return types.ResponseDeliverTx{Code: code.CodeTypeOK, Tags: tags} }

可以看出它會從輸入?yún)?shù)中解析出 key 和 value,最后保存在應用的 State 中。
當所有的 TX 被處理完之后需要調(diào)用 Commit 來更新整個區(qū)塊的狀態(tài),包括高度加 1 等:
tendermint的proposer節(jié)點選舉
概述
endermint的proposer節(jié)點選舉過程不需要網(wǎng)絡通信,而是根據(jù)config目錄下的genesis.json而決定的。genesis.json文件中有一個配置項是“validators”,這個key對應的是一個validator的列表,包含validator的pub_key和power。pub_key確定是哪個tendermint節(jié)點,power決定這個節(jié)點被選舉為proposer節(jié)點的頻率。
選舉算法詳解
1)加載并解析genesis.json,獲取每個節(jié)點的pub_key和power,power解析后保存在VotingPower中。
2)對每個validator的Accum進行賦值,Accum的值為驗證節(jié)點的權(quán)重值。

validatorsHeap := cmn.NewHeap()for _, val := range vals.Validators {// Check for overflow both multiplication and sum.val.Accum = safeAddClip(val.Accum, safeMulClip(val.VotingPower, int64(times)))validatorsHeap.PushComparable(val, accumComparable{val})}

3)選擇當次Accum值最大的為提議節(jié)點,同時對提議節(jié)點的的Accum值減去TotalVotinPower(所有驗證節(jié)點power的總和)

for i := 0; i < times; i++ {mostest := validatorsHeap.Peek().(*Validator)// mind underflowmostest.Accum = safeSubClip(mostest.Accum, vals.TotalVotingPower())if i == times-1 {vals.Proposer = mostest} else {validatorsHeap.Update(mostest, accumComparable{mostest})}}

注:上面的代碼中都有一個times變量,這個變量在正常運行中都是1。如果當前節(jié)點中途崩潰重啟過,則times是它落后于集群的選舉次數(shù)。
Tendermint Networks
Tendermint 網(wǎng)絡中節(jié)點有兩種類型:validator node 和 non-validator node。
If we want to add more nodes to the network, we have two choices: we can add a new validator node, who will also participate in the consensus by proposing blocks and voting on them, or we can add a new non-validator node, who will not participate directly, but will verify and keep up with the consensus protocol.
當 tendermint core 收到一個 rpc 交易請求,并完成共識之后,會給 app server 發(fā)送請求。
消息通訊
P2P模塊初始化的時候,也會初始化mempool reactor、blockchain reactor、consensus reactor、evidence reactor(還有上面講述的pex reactor),然后add到p2p模塊,不同的reactor帶不同的channel id

當mempool、blockchain、consensus、evidence模塊發(fā)送消息的時候,調(diào)用p2p模塊的send,參數(shù)有channel id

對端節(jié)點p2p模塊收到消息后,會根據(jù)channel id把消息轉(zhuǎn)發(fā)給對應的模塊

總結(jié)

以上是生活随笔為你收集整理的tendermint源码解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。