首先创建一个新的文件./app.go
。这个文件是确定性状态机的核心。
在app.go
中,你定义了应用程序在接收交易时执行的操作。但首先,它要能够以正确的顺序接收交易。这是 Tendermint共识引擎的职责。
引入必要的依赖:
package app
import (
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/x/auth"
bam "github.com/cosmos/cosmos-sdk/baseapp"
dbm "github.com/tendermint/tm-db"
)
下面是各引入模块和包的文档:
这里有几个包是tendermint
包。Tendermint 通过名为 ABCI 的接口将交易从网络传递给应用程序。如果你要查看正在构建的区块链节点的架构,如下所示:
+---------------------+
| |
| Application |
| |
+--------+---+--------+
^ |
| | ABCI
| v
+--------+---+--------+
| |
| |
| Tendermint |
| |
| |
+---------------------+
幸运的是,你不必实现ABCI接口。Cosmos SDK以baseapp
的形式提供了它的实现样板。
baseapp
做了以下几点:
- 解码从 Tendermint 共识引擎接收到的交易。
- 从交易中提取 messages 并做基本的合理性校验。
- 将这些 message 路由到合适的模块使其被正确处理。注意
baseapp
并不了解你想要使用的具体模块。你要做的就是在app.go
中声明这些模块,在接下来的教程中将会看到这些工作。baseapp
仅实现了适用于任意模块的核心路由逻辑。 - 如果 ABCI 消息是
DeliverTx
(CheckTx
)的话就Commit。 - 帮助设置
BeginBlock
和EndBlock
,这两种消息让你能定义在每个区块开始和结束时执行的逻辑。实际上,每个模块实现了各自的BeginBlock
和EndBlock
子逻辑,app的职责是它们都聚合起来。(注意:你不会在你的应用程序中使用这些消息) - 帮助初始化你的 state。
- 帮助设置 queries。
现在你需要为应用程序创建一个新的自定义类型nameServiceApp
。这个类型将嵌入baseapp
(在Go中的嵌入类似于其他语言中的继承),这意味着它可以访问baseapp
的所有方法。
const (
appName = "nameservice"
)
type nameServiceApp struct {
*bam.BaseApp
}
为你的应用添加一个简单的构造函数:
func NewNameServiceApp(logger log.Logger, db dbm.DB) *nameServiceApp {
// First define the top level codec that will be shared by the different modules. Note: Codec will be explained later
cdc := MakeCodec()
// BaseApp handles interactions with Tendermint through the ABCI protocol
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc))
var app = &nameServiceApp{
BaseApp: bApp,
cdc: cdc,
}
return app
}
很好!现在你有了应用程序的骨架;但是,仍然缺少具体功能。
baseapp
不了解你要在应用程序中使用的路由或用户交互。应用程序的主要作用是定义这些路由。另一个作用是定义初始状态。这两件事都要求你向应用程序添加模块。
正如你在应用程序设计章节中看到的,你的nameservice需要三个模块:auth
,bank
和nameservice
。前两个已经存在了,但最后一个还没有!nameservice
模块将定义你的状态机的大部分内容。下一步是构建它。
In order to complete your application, you need to include modules. Go ahead and start building your nameservice module. You will come back to app.go
later.