baseapp.go
Loc: baseapp/baseapp.go
ABCI应用的基本结构
// The ABCI application
type BaseApp struct {
// initialized on creation
Logger log.Logger
name string // application name from abci.Info
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
router Router // handle any kind of message
codespacer *sdk.Codespacer // handle module codespacing
// must be set
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
anteHandler sdk.AnteHandler // ante handler for fee and auth
// may be nil
initChainer sdk.InitChainer // initialize state with validators and state blob
beginBlocker sdk.BeginBlocker // logic to run before any txs
endBlocker sdk.EndBlocker // logic to run after all txs, and to determine valset changes
//--------------------
// Volatile
// checkState is set on initialization and reset on Commit.
// deliverState is set in InitChain and BeginBlock and cleared on Commit.
// See methods setCheckState and setDeliverState.
// .valUpdates accumulate in DeliverTx and are reset in BeginBlock.
// QUESTION: should we put valUpdates in the deliverState.ctx?
checkState *state // for CheckTx
deliverState *state // for DeliverTx
valUpdates []abci.Validator // cached validator changes from DeliverTx
}name就是应用的名称router路由选择正确的handler进行处理anteHandler每一笔交易都会执行手续费和验证的handlerbeginBlocker 和 endBlocker就是 对应的abci接口,一个在所有交易之前执行,一个是在交易执行之后执行。
checkState 和 deliverState表示的是当前处理的交易进入了什么阶段。
valUpdates 是缓存验证人集的更新,一般在endblocker的时候更新
ABCI 几个典型接口
上面就是一个DeliverTx的grpc调用的接口实现。 消息是通过go-amino序列化过所以他先用app.txDecoder(txBytes)解码,再调用runTx, 其实大部分交易tx 都是在runTx中处理的,然后返回处理结果。 app.valUpdates = append(...添加改变的验证人,最后把abci.ResponseDeliverTx返回给tendermint core
这时候大家肯定很好奇runTx里面到底做了什么? 让我继续跟踪吧(因为runtx函数源码很长所以我删去了一部分对理解没有关系的代码)
输入参数isCheckTx代表了这个runtx是checktx调用的还是delivertx调用的,因为这两个接口,有些操作和资源需求的是不一样的。但设计的时候delivertx和checktx都会走runtx。 GetMsg()获取msg,msg.validateBasic()验证交易合法性,ctx就相当于处理tx所需要的所有资源。msg.type()获取交易消息的类型。 handler := app.router.Route(msgType)这个就是根据交易信息类型选择handler,这个Route的具体应用就在这里,根据模块路由消息到对应的handler。handler(ctx,msg)开始调用你编写的handler.go里面的代码了(其实对应的handler肯定有一个参数会判别这个消息是checkt还是delivertx,因为上面说过他们两走一个,后面源码分析也会看到有一个变量决定了),返回消息处理的结果。所以在app.go对baseapp.go二次封装的时候,必定要要把自己模块的handler注册到router上。
注意 大家有没有注意到 antehandler,这个是不管是那个模块对应的交易消息都会执行的handler,我猜以后会实现手续费啊之类的。
总结
baseapp.go 定义了一个基本的abci应用的结构和接口。 用户具体的app.go(gaia)都是对baseapp.go的二次封装,添加注册模块。通过route来调用不同的模块的handler,各个模块相互独立。
Last updated