使用 ABCI-CLI
为了方便 ABCI 服务器和简单应用程序的测试和调试,我们构建了一个 CLI,即 abci-cli,用于从命令行发送 ABCI 消息。
安装
确保你已安装 Go.
接下来,安装 abci-cli 工具和示例应用程序:
mkdir -p $GOPATH/src/github.com/tendermintcd $GOPATH/src/github.com/tendermintgit clone https://github.com/tendermint/tendermint.gitcd tendermintmake get_toolsmake get_vendor_depsmake install_abci
现在运行 abci-cli 查看命令列表:
Usage:abci-cli [command]Available Commands:batch Run a batch of abci commands against an applicationcheck_tx Validate a txcommit Commit the application state and return the Merkle root hashconsole Start an interactive abci console for multiple commandscounter ABCI demo exampledeliver_tx Deliver a new tx to the applicationkvstore ABCI demo exampleecho Have the application echo a messagehelp Help about any commandinfo Get some info about the applicationquery Query the application stateset_option Set an options on the applicationFlags:--abci string socket or grpc (default "socket")--address string address of application socket (default "tcp://127.0.0.1:26658")-h, --help help for abci-cli-v, --verbose print the command and results as if it were a console sessionUse "abci-cli [command] --help" for more information about a command.
KVStore - 第一个例子
abci-cli 工具允许我们向应用程序发送 ABCI 消息,以帮助构建和调试它们。
最重要的消息是 deliver_tx、check_tx 和 commit,但出于方便、配置和信息目的,还有其他消息。
我们将启动一个 kvstore 应用程序,它与上面的 abci-cli 同时安装。kvstore 只是在默克尔树中存储交易。
它的代码可以在这里找到,看起来像:
func cmdKVStore(cmd *cobra.Command, args []string) error {logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))// Create the application - in memory or persisted to diskvar app types.Applicationif flagPersist == "" {app = kvstore.NewKVStoreApplication()} else {app = kvstore.NewPersistentKVStoreApplication(flagPersist)app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore"))}// Start the listenersrv, err := server.NewServer(flagAddrD, flagAbci, app)if err != nil {return err}srv.SetLogger(logger.With("module", "abci-server"))if err := srv.Start(); err != nil {return err}// Stop upon receiving SIGTERM or CTRL-C.cmn.TrapSignal(logger, func() {// Cleanupsrv.Stop()})// Run forever.select {}}
开始运行:
abci-cli kvstore
在另一个终端,运行
abci-cli echo helloabci-cli info
你会看到:
-> data: hello-> data.hex: 68656C6C6F
和:
-> data: {"size":0}-> data.hex: 7B2273697A65223A307D
ABCI 应用程序必须提供以下两点:
- 一个套接字服务器
- ABCI 消息的处理程序
当我们运行 abci-cli 工具时,我们打开到应用程序套接字服务器的新连接,发送给定的 ABCI 消息,并等待响应。
服务器可能是特定语言的通用服务器,我们提供了一个 Go 语言中的参考实现。查看其他语言服务器的其他 ABCI 实现列表。
处理程序是特定于应用程序的,并且可以是任意的,只要它是确定的并且符合 ABCI 接口规范。
因此,当我们运行 abci-cli info 时,我们打开到 ABCI 服务器的新连接,它调用应用程序上的 Info() 方法,该方法告诉我们默克尔树中的交易数。
现在,由于每个命令都打开一个新的连接,我们提供了 abci-cli console 和 abci-cli batch 命令,以允许通过一个连接发送多个 ABCI 消息。
运行 abci-cli console 应该会将您置于一个交互式控制台中,用于向您的应用程序发出 ABCI 消息。
尝试运行以下命令:
> echo hello-> code: OK-> data: hello-> data.hex: 0x68656C6C6F> info-> code: OK-> data: {"size":0}-> data.hex: 0x7B2273697A65223A307D> commit-> code: OK-> data.hex: 0x0000000000000000> deliver_tx "abc"-> code: OK> info-> code: OK-> data: {"size":1}-> data.hex: 0x7B2273697A65223A317D> commit-> code: OK-> data.hex: 0x0200000000000000> query "abc"-> code: OK-> log: exists-> height: 0-> value: abc-> value.hex: 616263> deliver_tx "def=xyz"-> code: OK> commit-> code: OK-> data.hex: 0x0400000000000000> query "def"-> code: OK-> log: exists-> height: 0-> value: xyz-> value.hex: 78797A
注意,如果我们执行 deliver_tx "abc" 操作,它将存储 (abc, abc),但是如果执行 deliver_tx "abc=efg" 操作,它将存储(abc, efg)。
类似地,您可以将命令放入文件中并运行 abci-cli --verbose batch < myfile。
Counter - 另一个例子
现在我们已经掌握了窍门,让我们尝试另一个应用程序,”counter” 应用程序。
和 kvstore 应用程序一样,它的代码可以在这里找到,如下所示:
func cmdCounter(cmd *cobra.Command, args []string) error {app := counter.NewCounterApplication(flagSerial)logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))// Start the listenersrv, err := server.NewServer(flagAddrC, flagAbci, app)if err != nil {return err}srv.SetLogger(logger.With("module", "abci-server"))if err := srv.Start(); err != nil {return err}// Stop upon receiving SIGTERM or CTRL-C.cmn.TrapSignal(logger, func() {// Cleanupsrv.Stop()})// Run forever.select {}}
计数器应用程序不使用默克尔树,它只计算我们发送交易、请求哈希或提交状态的次数。commit 的结果就是发送的交易数。
这个应用程序有两种模式:serial=off 和 serial=on。
当 serial=on 时,交易必须是一个以大端编码的递增整数,从 0 开始。
如果 serial=off,则对交易没有限制。
我们可以使用 set_option ABCI 消息切换 serial 的值。
当 serial=on 时,一些交易是无效的。在活动的区块链中,交易在提交到块之前收集到内存中。为了避免在无效的交易上浪费资源,ABCI 提供了 check_tx 消息,应用程序开发人员可以使用该消息来接受或拒绝交易,然后再将交易存储在内存中或传递给其他节点。
在计数器应用程序的这个实例中,check_tx 只允许整数大于最后提交的整数的交易。
让我们关闭控制台和 kvstore 应用程序,启动 counter 应用程序:
abci-cli counter
在另一个窗口,启动 abci-cli console:
> set_option serial on-> code: OK-> log: OK (SetOption doesn't return anything.)> check_tx 0x00-> code: OK> check_tx 0xff-> code: OK> deliver_tx 0x00-> code: OK> check_tx 0x00-> code: BadNonce-> log: Invalid nonce. Expected >= 1, got 0> deliver_tx 0x01-> code: OK> deliver_tx 0x04-> code: BadNonce-> log: Invalid nonce. Expected 2, got 4> info-> code: OK-> data: {"hashes":0,"txs":2}-> data.hex: 0x7B22686173686573223A302C22747873223A327D
这是一个非常简单的应用程序,但是在 counter 和 kvstore 之间,很容易看到如何在 ABCI 之上构建任意的应用程序状态。Hyperledger’s Burrow 也运行在 ABCI 之上,带来了类似以太的账户、以太虚拟机、Monax 的许可方案和本地契约扩展。
但是,最终的灵活性来自能够用任何语言轻松编写应用程序。
我们已经用多种语言实现了计数器参见示例目录。
要运行 Node JS 版本,cd 到 example/js 并运行
node app.js
(您必须终止另一个计数器应用程序)。在另一个窗口中,运行控制台和前面的 ABCI 命令。您应该得到与 Go 版本相同的结果。
赏金
想用你最喜欢的语言编写计数器应用程序?!我们很乐意将您加入我们的生态系统!我们还为新语言的实现提供奖励!
abci-cli 严格设计用于测试和调试。在实际部署中,发送消息的角色由 Tendermint 承担,它使用三个独立的连接连接到应用程序,每个连接都有自己的消息模式。
有关更多信息,请参见应用程序开发人员指南。要运行带有 Tendermint 的 ABCI 应用程序,请参阅入门指南。 接下来是 ABCI 规范。
