概述 与节点交互有多种方式:使用 CLI、gRPC 或 REST 端点。

使用 CLI

现在你的链已经运行起来了,是时候尝试将你创建的第一个账户中的代币发送到第二个账户。在新的终端窗口中,先运行以下查询命令:
simd query bank balances $MY_VALIDATOR_ADDRESS
你应该会看到你创建的账户当前余额,等于最初分配给它的 stake 余额减去你通过 gentx 委托出去的数量。接下来,创建第二个账户:
simd keys add recipient --keyring-backend test


# Put the generated address in a variable for later use.
RECIPIENT=$(simd keys show recipient -a --keyring-backend test)
上面的命令会创建一个本地密钥对,但它尚未在链上注册。账户会在第一次从其他账户接收代币时创建。现在,运行以下命令向 recipient 账户发送代币:
simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000000stake --chain-id my-test-chain --keyring-backend test


# Check that the recipient account did receive the tokens.
simd query bank balances $RECIPIENT
添加 -y 或 --yes 标志可以跳过确认提示,这对脚本和自动化场景很有用:
simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000000stake --chain-id my-test-chain --keyring-backend test -y
最后,将发送到 recipient 账户中的部分 stake 代币委托给验证者:
simd tx staking delegate $(simd keys show my_validator --bech val -a --keyring-backend test) 500stake --from recipient --chain-id my-test-chain --keyring-backend test


# Query the total delegations to `validator`.
simd query staking delegations-to $(simd keys show my_validator --bech val -a --keyring-backend test)
你应该会看到两笔委托,第一笔来自 gentx,第二笔是你刚刚从 recipient 账户执行的委托。

使用 gRPC

Protobuf 生态为不同使用场景开发了多种工具,包括从 *.proto 文件生成多种语言代码的工具。这些工具可以让你更容易地构建客户端。通常,客户端连接(即传输层)也可以非常方便地插拔和替换。本节将介绍最流行的传输方式之一:gRPC。 由于代码生成库在很大程度上取决于你自己的技术栈,这里提供三种选择:
  • 用于通用调试和测试的 grpcurl
  • 通过 Go 以编程方式调用
  • 面向 JavaScript/TypeScript 开发者的 CosmJS

grpcurl

grpcurl 类似于 curl,但用于 gRPC。它也可以作为 Go 库使用,但本教程只将其作为 CLI 命令用于调试和测试。请按照前面链接中的说明进行安装。 假设你已经有一个正在运行的本地节点(无论是 localnet,还是连接到实时网络),你应该可以运行以下命令来列出可用的 Protobuf 服务(你也可以将 localhost:9090 替换为其他节点的 gRPC 服务端点,该端点配置在 app.toml 中的 grpc.address 字段下):
grpcurl -plaintext localhost:9090 list
你应该会看到一个 gRPC 服务列表,例如 cosmos.bank.v1beta1.Query。这称为反射,它是一个返回所有可用端点描述的 Protobuf 端点。每一项都代表一个不同的 Protobuf 服务,而每个服务又暴露出多个可供查询的 RPC 方法。 要获取某个服务的描述,可以运行以下命令:
grpcurl -plaintext \
    localhost:9090 \
    describe cosmos.bank.v1beta1.Query                  # Service we want to inspect
你也可以执行 RPC 调用来向节点查询信息:
grpcurl \
    -plaintext \
    -d "{\"address\":\"$MY_VALIDATOR_ADDRESS\"}" \
    localhost:9090 \
    cosmos.bank.v1beta1.Query/AllBalances
所有可用的 gRPC 查询端点列表将很快提供。

使用 grpcurl 查询历史状态

你也可以通过向查询传递一些 gRPC 元数据 来查询历史数据:x-cosmos-block-height 元数据应包含要查询的区块高度。以上述 grpcurl 用法为例,命令如下:
grpcurl \
    -plaintext \
    -H "x-cosmos-block-height: 123" \
    -d "{\"address\":\"$MY_VALIDATOR_ADDRESS\"}" \
    localhost:9090 \
    cosmos.bank.v1beta1.Query/AllBalances
假设该区块对应的状态尚未被节点裁剪,此查询应返回非空响应。

通过 Go 以编程方式调用

下面的代码片段展示了如何在 Go 程序中使用 gRPC 查询状态。思路是创建一个 gRPC 连接,然后使用 Protobuf 生成的客户端代码查询 gRPC 服务器。

安装 Cosmos SDK

go get github.com/cosmos/cosmos-sdk@main
package main

import (
    
    "context"
    "fmt"
    "google.golang.org/grpc"
    "github.com/cosmos/cosmos-sdk/codec"
    sdk "github.com/cosmos/cosmos-sdk/types"
    banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func queryState()

error {
    myAddress, err := sdk.AccAddressFromBech32("cosmos1...") // the my_validator or recipient address.
    if err != nil {
    return err
}

    // Create a connection to the gRPC server.
    grpcConn, err := grpc.Dial(
        "127.0.0.1:9090", // your gRPC server address.
        grpc.WithInsecure(), // The Cosmos SDK doesn't support any transport security mechanisms. 
        // This instantiates a general gRPC codec which handles proto bytes. We pass in a nil interface registry
        // if the request/response types contain an interface instead of 'nil' you should pass the application specific codec.
		grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec())),
	)
    if err != nil {
    return err
}

defer grpcConn.Close()

    // This creates a gRPC client to query the x/bank service.
    bankClient := banktypes.NewQueryClient(grpcConn)

bankRes, err := bankClient.Balance(
        context.Background(),
        &banktypes.QueryBalanceRequest{
    Address: myAddress.String(),
    Denom: "stake"
},
    )
    if err != nil {
    return err
}

fmt.Println(bankRes.GetBalance()) // Prints the account balance

    return nil
}

func main() {
    if err := queryState(); err != nil {
    panic(err)
}
}
你可以将这里使用的查询客户端(此处为 x/bank)替换为任何其他 Protobuf 服务生成的客户端。所有可用的 gRPC 查询端点列表将很快提供。

使用 Go 查询历史状态

查询历史区块的方式是在 gRPC 请求中添加区块高度元数据。
package main

import (
    
	"context"
    "fmt"
    "google.golang.org/grpc"
    "google.golang.org/grpc/metadata"
    "github.com/cosmos/cosmos-sdk/codec"
	sdk "github.com/cosmos/cosmos-sdk/types"
	grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func queryState()

error {
    myAddress, err := sdk.AccAddressFromBech32("cosmos1yerherx4d43gj5wa3zl5vflj9d4pln42n7kuzu") // the my_validator or recipient address.
    if err != nil {
    return err
}

	// Create a connection to the gRPC server.
	grpcConn, err := grpc.Dial(
		"127.0.0.1:9090",    // your gRPC server address.
		grpc.WithInsecure(), // The Cosmos SDK doesn't support any transport security mechanisms.
		// This instantiates a general gRPC codec which handles proto bytes. We pass in a nil interface registry
		// if the request/response types contain an interface instead of 'nil' you should pass the application specific codec.
		grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec())),
	)
    if err != nil {
    return err
}

defer grpcConn.Close()

	// This creates a gRPC client to query the x/bank service.
    bankClient := banktypes.NewQueryClient(grpcConn)

var header metadata.MD
	_, err = bankClient.Balance(
		metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, "12"), // Add metadata to request
		&banktypes.QueryBalanceRequest{
    Address: myAddress.String(),
    Denom: "stake"
},
		grpc.Header(&header), // Retrieve header from response
	)
    if err != nil {
    return err
}
    blockHeight := header.Get(grpctypes.GRPCBlockHeightHeader)

fmt.Println(blockHeight) // Prints the block height (12)

return nil
}

func main() {
    if err := queryState(); err != nil {
    panic(err)
}
}

CosmJS

CosmJS 文档可见于 Link。

使用 REST 端点

如 gRPC 指南 中所述,Cosmos SDK 上的所有 gRPC 服务都会通过 gRPC-gateway 以更便捷的 REST 查询方式提供。URL 路径的格式基于 Protobuf 服务方法的完全限定名,但可能会包含一些小的自定义,以便最终 URL 看起来更符合习惯用法。例如,cosmos.bank.v1beta1.Query/AllBalances 方法对应的 REST 端点是 GET /cosmos/bank/v1beta1/balances/{address}。请求参数通过查询参数传递。 请注意,REST 端点默认未启用。要启用它们,请编辑 ~/.simapp/config/app.toml 文件中的 api 部分:

# Enable defines if the API server should be enabled.
enable = true
启用 API 后,你必须重启节点,配置更改才会生效。使用 Ctrl+C 停止节点,然后再次运行 simd start。
作为一个具体示例,用于发起余额查询请求的 curl 命令如下:
curl \
    -X GET \
    -H "Content-Type: application/json" \
    http://localhost:1317/cosmos/bank/v1beta1/balances/$MY_VALIDATOR_ADDRESS
请确保将 localhost:1317 替换为你的节点 REST 端点,该端点配置在 api.address 字段下。 所有可用 REST 端点的列表可通过 Swagger 规范文件获得,可在 localhost:1317/swagger 查看。请确保你的 app.toml 文件中 api.swagger 字段设置为 true。

使用 REST 查询历史状态

查询历史状态的方式是使用 HTTP 请求头 x-cosmos-block-height。例如,curl 命令如下:
curl \
    -X GET \
    -H "Content-Type: application/json" \
    -H "x-cosmos-block-height: 123" \
    http://localhost:1317/cosmos/bank/v1beta1/balances/$MY_VALIDATOR_ADDRESS
假设该区块对应的状态尚未被节点裁剪,此查询应返回非空响应。

跨域资源共享(CORS)

默认未启用 CORS 策略 以帮助提升安全性。如果你希望在公共环境中使用 rest-server,我们建议你提供一个反向代理,可通过 nginx 实现。对于测试和开发场景,app.toml 中有一个 enabled-unsafe-cors 字段。

恭喜!

你已经成功通过 CLI、gRPC 和 REST 端点与你的 Cosmos SDK 节点进行交互。现在,你可以通过多种接口查询状态并提交交易。

后续步骤


Synopsis There are multiple ways to interact with a node: using the CLI, gRPC, or REST endpoints.

Using the CLI

Now that your chain is running, it is time to try sending tokens from the first account you created to a second account. In a new terminal window, start by running the following query command:
simd query bank balances $MY_VALIDATOR_ADDRESS
You should see the current balance of the account you created, equal to the original balance of stake you granted it minus the amount you delegated via the gentx. Now, create a second account:
simd keys add recipient --keyring-backend test

# Put the generated address in a variable for later use.
RECIPIENT=$(simd keys show recipient -a --keyring-backend test)
The command above creates a local key-pair that is not yet registered on the chain. An account is created the first time it receives tokens from another account. Now, run the following command to send tokens to the recipient account:
simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000000stake --chain-id my-test-chain --keyring-backend test

# Check that the recipient account did receive the tokens.
simd query bank balances $RECIPIENT
Add the -y or --yes flag to skip the confirmation prompt, which is useful for scripts and automation:
simd tx bank send $MY_VALIDATOR_ADDRESS $RECIPIENT 1000000stake --chain-id my-test-chain --keyring-backend test -y
Finally, delegate some of the stake tokens sent to the recipient account to the validator:
simd tx staking delegate $(simd keys show my_validator --bech val -a --keyring-backend test) 500stake --from recipient --chain-id my-test-chain --keyring-backend test

# Query the total delegations to `validator`.
simd query staking delegations-to $(simd keys show my_validator --bech val -a --keyring-backend test)
You should see two delegations, the first one made from the gentx, and the second one you just performed from the recipient account.

Using gRPC

The Protobuf ecosystem developed tools for different use cases, including code-generation from *.proto files into various languages. These tools allow the building of clients easily. Often, the client connection (i.e. the transport) can be plugged and replaced very easily. This section explores one of the most popular transports: gRPC. Since the code generation library largely depends on your own tech stack, three alternatives are presented:
  • grpcurl for generic debugging and testing,
  • programmatically via Go,
  • CosmJS for JavaScript/TypeScript developers.

grpcurl

grpcurl is like curl but for gRPC. It is also available as a Go library, but this tutorial uses it only as a CLI command for debugging and testing purposes. Follow the instructions in the previous link to install it. Assuming you have a local node running (either a localnet, or connected to a live network), you should be able to run the following command to list the Protobuf services available (you can replace localhost:9090 with the gRPC server endpoint of another node, which is configured under the grpc.address field inside app.toml):
grpcurl -plaintext localhost:9090 list
You should see a list of gRPC services, like cosmos.bank.v1beta1.Query. This is called reflection, which is a Protobuf endpoint returning a description of all available endpoints. Each of these represents a different Protobuf service, and each service exposes multiple RPC methods you can query against. In order to get a description of the service you can run the following command:
grpcurl -plaintext \
    localhost:9090 \
    describe cosmos.bank.v1beta1.Query                  # Service we want to inspect
It’s also possible to execute an RPC call to query the node for information:
grpcurl \
    -plaintext \
    -d "{\"address\":\"$MY_VALIDATOR_ADDRESS\"}" \
    localhost:9090 \
    cosmos.bank.v1beta1.Query/AllBalances
The list of all available gRPC query endpoints is coming soon.

Query for historical state using grpcurl

You may also query for historical data by passing some gRPC metadata to the query: the x-cosmos-block-height metadata should contain the block to query. Using grpcurl as above, the command looks like:
grpcurl \
    -plaintext \
    -H "x-cosmos-block-height: 123" \
    -d "{\"address\":\"$MY_VALIDATOR_ADDRESS\"}" \
    localhost:9090 \
    cosmos.bank.v1beta1.Query/AllBalances
Assuming the state at that block has not yet been pruned by the node, this query should return a non-empty response.

Programmatically via Go

The following snippet shows how to query the state using gRPC inside a Go program. The idea is to create a gRPC connection, and use the Protobuf-generated client code to query the gRPC server.

Install Cosmos SDK

go get github.com/cosmos/cosmos-sdk@main
package main

import (
    
    "context"
    "fmt"
    "google.golang.org/grpc"
    "github.com/cosmos/cosmos-sdk/codec"
    sdk "github.com/cosmos/cosmos-sdk/types"
    banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func queryState()

error {
    myAddress, err := sdk.AccAddressFromBech32("cosmos1...") // the my_validator or recipient address.
    if err != nil {
    return err
}

    // Create a connection to the gRPC server.
    grpcConn, err := grpc.Dial(
        "127.0.0.1:9090", // your gRPC server address.
        grpc.WithInsecure(), // The Cosmos SDK doesn't support any transport security mechanisms. 
        // This instantiates a general gRPC codec which handles proto bytes. We pass in a nil interface registry
        // if the request/response types contain an interface instead of 'nil' you should pass the application specific codec.
		grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec())),
	)
    if err != nil {
    return err
}

defer grpcConn.Close()

    // This creates a gRPC client to query the x/bank service.
    bankClient := banktypes.NewQueryClient(grpcConn)

bankRes, err := bankClient.Balance(
        context.Background(),
        &banktypes.QueryBalanceRequest{
    Address: myAddress.String(),
    Denom: "stake"
},
    )
    if err != nil {
    return err
}

fmt.Println(bankRes.GetBalance()) // Prints the account balance

    return nil
}

func main() {
    if err := queryState(); err != nil {
    panic(err)
}
}
You can replace the query client (here we are using x/bank’s) with one generated from any other Protobuf service. The list of all available gRPC query endpoints is coming soon.

Query for historical state using Go

Querying for historical blocks is done by adding the block height metadata in the gRPC request.
package main

import (
    
	"context"
    "fmt"
    "google.golang.org/grpc"
    "google.golang.org/grpc/metadata"
    "github.com/cosmos/cosmos-sdk/codec"
	sdk "github.com/cosmos/cosmos-sdk/types"
	grpctypes "github.com/cosmos/cosmos-sdk/types/grpc"
	banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

func queryState()

error {
    myAddress, err := sdk.AccAddressFromBech32("cosmos1yerherx4d43gj5wa3zl5vflj9d4pln42n7kuzu") // the my_validator or recipient address.
    if err != nil {
    return err
}

	// Create a connection to the gRPC server.
	grpcConn, err := grpc.Dial(
		"127.0.0.1:9090",    // your gRPC server address.
		grpc.WithInsecure(), // The Cosmos SDK doesn't support any transport security mechanisms.
		// This instantiates a general gRPC codec which handles proto bytes. We pass in a nil interface registry
		// if the request/response types contain an interface instead of 'nil' you should pass the application specific codec.
		grpc.WithDefaultCallOptions(grpc.ForceCodec(codec.NewProtoCodec(nil).GRPCCodec())),
	)
    if err != nil {
    return err
}

defer grpcConn.Close()

	// This creates a gRPC client to query the x/bank service.
    bankClient := banktypes.NewQueryClient(grpcConn)

var header metadata.MD
	_, err = bankClient.Balance(
		metadata.AppendToOutgoingContext(context.Background(), grpctypes.GRPCBlockHeightHeader, "12"), // Add metadata to request
		&banktypes.QueryBalanceRequest{
    Address: myAddress.String(),
    Denom: "stake"
},
		grpc.Header(&header), // Retrieve header from response
	)
    if err != nil {
    return err
}
    blockHeight := header.Get(grpctypes.GRPCBlockHeightHeader)

fmt.Println(blockHeight) // Prints the block height (12)

return nil
}

func main() {
    if err := queryState(); err != nil {
    panic(err)
}
}

CosmJS

CosmJS documentation can be found at Link.

Using the REST Endpoints

As described in the gRPC guide, all gRPC services on the Cosmos SDK are made available for more convenient REST-based queries through gRPC-gateway. The format of the URL path is based on the Protobuf service method’s full-qualified name, but may contain small customizations so that final URLs look more idiomatic. For example, the REST endpoint for the cosmos.bank.v1beta1.Query/AllBalances method is GET /cosmos/bank/v1beta1/balances/{address}. Request arguments are passed as query parameters. Note that the REST endpoints are not enabled by default. To enable them, edit the api section of your ~/.simapp/config/app.toml file:
# Enable defines if the API server should be enabled.
enable = true
After enabling the API, you must restart your node for the changes to take effect. Stop the node with Ctrl+C and run simd start again.
As a concrete example, the curl command to make balances request is:
curl \
    -X GET \
    -H "Content-Type: application/json" \
    http://localhost:1317/cosmos/bank/v1beta1/balances/$MY_VALIDATOR_ADDRESS
Make sure to replace localhost:1317 with the REST endpoint of your node, configured under the api.address field. The list of all available REST endpoints is available as a Swagger specification file, which can be viewed at localhost:1317/swagger. Make sure that the api.swagger field is set to true in your app.toml file.

Query for historical state using REST

Querying for historical state is done using the HTTP header x-cosmos-block-height. For example, a curl command would look like:
curl \
    -X GET \
    -H "Content-Type: application/json" \
    -H "x-cosmos-block-height: 123" \
    http://localhost:1317/cosmos/bank/v1beta1/balances/$MY_VALIDATOR_ADDRESS
Assuming the state at that block has not yet been pruned by the node, this query should return a non-empty response.

Cross-Origin Resource Sharing (CORS)

CORS policies are not enabled by default to help with security. If you would like to use the rest-server in a public environment, we recommend you provide a reverse proxy, which can be done with nginx. For testing and development purposes, there is an enabled-unsafe-cors field inside app.toml.

Congratulations!

You have successfully interacted with your Cosmos SDK node using the CLI, gRPC, and REST endpoints. You can now query state and submit transactions through multiple interfaces.

Next steps