使用 ABCI-CLI

为了方便 ABCI 服务器和简单应用程序的测试和调试,我们构建了一个 CLI,即 abci-cli,用于从命令行发送 ABCI 消息。

安装

确保你已安装 Go.

接下来,安装 abci-cli 工具和示例应用程序:

  1. mkdir -p $GOPATH/src/github.com/tendermint
  2. cd $GOPATH/src/github.com/tendermint
  3. git clone https://github.com/tendermint/tendermint.git
  4. cd tendermint
  5. make get_tools
  6. make get_vendor_deps
  7. make install_abci

现在运行 abci-cli 查看命令列表:

  1. Usage:
  2. abci-cli [command]
  3. Available Commands:
  4. batch Run a batch of abci commands against an application
  5. check_tx Validate a tx
  6. commit Commit the application state and return the Merkle root hash
  7. console Start an interactive abci console for multiple commands
  8. counter ABCI demo example
  9. deliver_tx Deliver a new tx to the application
  10. kvstore ABCI demo example
  11. echo Have the application echo a message
  12. help Help about any command
  13. info Get some info about the application
  14. query Query the application state
  15. set_option Set an options on the application
  16. Flags:
  17. --abci string socket or grpc (default "socket")
  18. --address string address of application socket (default "tcp://127.0.0.1:26658")
  19. -h, --help help for abci-cli
  20. -v, --verbose print the command and results as if it were a console session
  21. Use "abci-cli [command] --help" for more information about a command.

KVStore - 第一个例子

abci-cli 工具允许我们向应用程序发送 ABCI 消息,以帮助构建和调试它们。

最重要的消息是 deliver_txcheck_txcommit,但出于方便、配置和信息目的,还有其他消息。

我们将启动一个 kvstore 应用程序,它与上面的 abci-cli 同时安装。kvstore 只是在默克尔树中存储交易。

它的代码可以在这里找到,看起来像:

  1. func cmdKVStore(cmd *cobra.Command, args []string) error {
  2. logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
  3. // Create the application - in memory or persisted to disk
  4. var app types.Application
  5. if flagPersist == "" {
  6. app = kvstore.NewKVStoreApplication()
  7. } else {
  8. app = kvstore.NewPersistentKVStoreApplication(flagPersist)
  9. app.(*kvstore.PersistentKVStoreApplication).SetLogger(logger.With("module", "kvstore"))
  10. }
  11. // Start the listener
  12. srv, err := server.NewServer(flagAddrD, flagAbci, app)
  13. if err != nil {
  14. return err
  15. }
  16. srv.SetLogger(logger.With("module", "abci-server"))
  17. if err := srv.Start(); err != nil {
  18. return err
  19. }
  20. // Stop upon receiving SIGTERM or CTRL-C.
  21. cmn.TrapSignal(logger, func() {
  22. // Cleanup
  23. srv.Stop()
  24. })
  25. // Run forever.
  26. select {}
  27. }

开始运行:

  1. abci-cli kvstore

在另一个终端,运行

  1. abci-cli echo hello
  2. abci-cli info

你会看到:

  1. -> data: hello
  2. -> data.hex: 68656C6C6F

和:

  1. -> data: {"size":0}
  2. -> data.hex: 7B2273697A65223A307D

ABCI 应用程序必须提供以下两点:

  • 一个套接字服务器
  • ABCI 消息的处理程序

当我们运行 abci-cli 工具时,我们打开到应用程序套接字服务器的新连接,发送给定的 ABCI 消息,并等待响应。

服务器可能是特定语言的通用服务器,我们提供了一个 Go 语言中的参考实现。查看其他语言服务器的其他 ABCI 实现列表

处理程序是特定于应用程序的,并且可以是任意的,只要它是确定的并且符合 ABCI 接口规范。

因此,当我们运行 abci-cli info 时,我们打开到 ABCI 服务器的新连接,它调用应用程序上的 Info() 方法,该方法告诉我们默克尔树中的交易数。

现在,由于每个命令都打开一个新的连接,我们提供了 abci-cli consoleabci-cli batch 命令,以允许通过一个连接发送多个 ABCI 消息。

运行 abci-cli console 应该会将您置于一个交互式控制台中,用于向您的应用程序发出 ABCI 消息。

尝试运行以下命令:

  1. > echo hello
  2. -> code: OK
  3. -> data: hello
  4. -> data.hex: 0x68656C6C6F
  5. > info
  6. -> code: OK
  7. -> data: {"size":0}
  8. -> data.hex: 0x7B2273697A65223A307D
  9. > commit
  10. -> code: OK
  11. -> data.hex: 0x0000000000000000
  12. > deliver_tx "abc"
  13. -> code: OK
  14. > info
  15. -> code: OK
  16. -> data: {"size":1}
  17. -> data.hex: 0x7B2273697A65223A317D
  18. > commit
  19. -> code: OK
  20. -> data.hex: 0x0200000000000000
  21. > query "abc"
  22. -> code: OK
  23. -> log: exists
  24. -> height: 0
  25. -> value: abc
  26. -> value.hex: 616263
  27. > deliver_tx "def=xyz"
  28. -> code: OK
  29. > commit
  30. -> code: OK
  31. -> data.hex: 0x0400000000000000
  32. > query "def"
  33. -> code: OK
  34. -> log: exists
  35. -> height: 0
  36. -> value: xyz
  37. -> value.hex: 78797A

注意,如果我们执行 deliver_tx "abc" 操作,它将存储 (abc, abc),但是如果执行 deliver_tx "abc=efg" 操作,它将存储(abc, efg)

类似地,您可以将命令放入文件中并运行 abci-cli --verbose batch < myfile

Counter - 另一个例子

现在我们已经掌握了窍门,让我们尝试另一个应用程序,”counter” 应用程序。

和 kvstore 应用程序一样,它的代码可以在这里找到,如下所示:

  1. func cmdCounter(cmd *cobra.Command, args []string) error {
  2. app := counter.NewCounterApplication(flagSerial)
  3. logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
  4. // Start the listener
  5. srv, err := server.NewServer(flagAddrC, flagAbci, app)
  6. if err != nil {
  7. return err
  8. }
  9. srv.SetLogger(logger.With("module", "abci-server"))
  10. if err := srv.Start(); err != nil {
  11. return err
  12. }
  13. // Stop upon receiving SIGTERM or CTRL-C.
  14. cmn.TrapSignal(logger, func() {
  15. // Cleanup
  16. srv.Stop()
  17. })
  18. // Run forever.
  19. select {}
  20. }

计数器应用程序不使用默克尔树,它只计算我们发送交易、请求哈希或提交状态的次数。commit 的结果就是发送的交易数。

这个应用程序有两种模式:serial=offserial=on

serial=on 时,交易必须是一个以大端编码的递增整数,从 0 开始。

如果 serial=off,则对交易没有限制。

我们可以使用 set_option ABCI 消息切换 serial 的值。

serial=on 时,一些交易是无效的。在活动的区块链中,交易在提交到块之前收集到内存中。为了避免在无效的交易上浪费资源,ABCI 提供了 check_tx 消息,应用程序开发人员可以使用该消息来接受或拒绝交易,然后再将交易存储在内存中或传递给其他节点。

在计数器应用程序的这个实例中,check_tx 只允许整数大于最后提交的整数的交易。

让我们关闭控制台和 kvstore 应用程序,启动 counter 应用程序:

  1. abci-cli counter

在另一个窗口,启动 abci-cli console

  1. > set_option serial on
  2. -> code: OK
  3. -> log: OK (SetOption doesn't return anything.)
  4. > check_tx 0x00
  5. -> code: OK
  6. > check_tx 0xff
  7. -> code: OK
  8. > deliver_tx 0x00
  9. -> code: OK
  10. > check_tx 0x00
  11. -> code: BadNonce
  12. -> log: Invalid nonce. Expected >= 1, got 0
  13. > deliver_tx 0x01
  14. -> code: OK
  15. > deliver_tx 0x04
  16. -> code: BadNonce
  17. -> log: Invalid nonce. Expected 2, got 4
  18. > info
  19. -> code: OK
  20. -> data: {"hashes":0,"txs":2}
  21. -> data.hex: 0x7B22686173686573223A302C22747873223A327D

这是一个非常简单的应用程序,但是在 counterkvstore 之间,很容易看到如何在 ABCI 之上构建任意的应用程序状态。Hyperledger’s Burrow 也运行在 ABCI 之上,带来了类似以太的账户、以太虚拟机、Monax 的许可方案和本地契约扩展。

但是,最终的灵活性来自能够用任何语言轻松编写应用程序。

我们已经用多种语言实现了计数器参见示例目录

要运行 Node JS 版本,cdexample/js 并运行

  1. node app.js

(您必须终止另一个计数器应用程序)。在另一个窗口中,运行控制台和前面的 ABCI 命令。您应该得到与 Go 版本相同的结果。

赏金

想用你最喜欢的语言编写计数器应用程序?!我们很乐意将您加入我们的生态系统!我们还为新语言的实现提供奖励

abci-cli 严格设计用于测试和调试。在实际部署中,发送消息的角色由 Tendermint 承担,它使用三个独立的连接连接到应用程序,每个连接都有自己的消息模式。

有关更多信息,请参见应用程序开发人员指南。要运行带有 Tendermint 的 ABCI 应用程序,请参阅入门指南。 接下来是 ABCI 规范。